1// Copyright 2015 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// This file implements encoding/decoding of Rats. 6 7package big 8 9import ( 10 "errors" 11 "fmt" 12 "internal/byteorder" 13 "math" 14) 15 16// Gob codec version. Permits backward-compatible changes to the encoding. 17const ratGobVersion byte = 1 18 19// GobEncode implements the [encoding/gob.GobEncoder] interface. 20func (x *Rat) GobEncode() ([]byte, error) { 21 if x == nil { 22 return nil, nil 23 } 24 buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4) 25 i := x.b.abs.bytes(buf) 26 j := x.a.abs.bytes(buf[:i]) 27 n := i - j 28 if int(uint32(n)) != n { 29 // this should never happen 30 return nil, errors.New("Rat.GobEncode: numerator too large") 31 } 32 byteorder.BePutUint32(buf[j-4:j], uint32(n)) 33 j -= 1 + 4 34 b := ratGobVersion << 1 // make space for sign bit 35 if x.a.neg { 36 b |= 1 37 } 38 buf[j] = b 39 return buf[j:], nil 40} 41 42// GobDecode implements the [encoding/gob.GobDecoder] interface. 43func (z *Rat) GobDecode(buf []byte) error { 44 if len(buf) == 0 { 45 // Other side sent a nil or default value. 46 *z = Rat{} 47 return nil 48 } 49 if len(buf) < 5 { 50 return errors.New("Rat.GobDecode: buffer too small") 51 } 52 b := buf[0] 53 if b>>1 != ratGobVersion { 54 return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) 55 } 56 const j = 1 + 4 57 ln := byteorder.BeUint32(buf[j-4 : j]) 58 if uint64(ln) > math.MaxInt-j { 59 return errors.New("Rat.GobDecode: invalid length") 60 } 61 i := j + int(ln) 62 if len(buf) < i { 63 return errors.New("Rat.GobDecode: buffer too small") 64 } 65 z.a.neg = b&1 != 0 66 z.a.abs = z.a.abs.setBytes(buf[j:i]) 67 z.b.abs = z.b.abs.setBytes(buf[i:]) 68 return nil 69} 70 71// MarshalText implements the [encoding.TextMarshaler] interface. 72func (x *Rat) MarshalText() (text []byte, err error) { 73 if x.IsInt() { 74 return x.a.MarshalText() 75 } 76 return x.marshal(), nil 77} 78 79// UnmarshalText implements the [encoding.TextUnmarshaler] interface. 80func (z *Rat) UnmarshalText(text []byte) error { 81 // TODO(gri): get rid of the []byte/string conversion 82 if _, ok := z.SetString(string(text)); !ok { 83 return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text) 84 } 85 return nil 86} 87