ratmarsh.mx raw
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
7 package big
8
9 import (
10 "errors"
11 "fmt"
12 "internal/byteorder"
13 "math"
14 )
15
16 // Gob codec version. Permits backward-compatible changes to the encoding.
17 const ratGobVersion byte = 1
18
19 // GobEncode implements the [encoding/gob.GobEncoder] interface.
20 func (x *Rat) GobEncode() ([]byte, error) {
21 if x == nil {
22 return nil, nil
23 }
24 buf := []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.
43 func (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 // AppendText implements the [encoding.TextAppender] interface.
72 func (x *Rat) AppendText(b []byte) ([]byte, error) {
73 if x.IsInt() {
74 return x.a.AppendText(b)
75 }
76 return x.marshal(b), nil
77 }
78
79 // MarshalText implements the [encoding.TextMarshaler] interface.
80 func (x *Rat) MarshalText() (text []byte, err error) {
81 return x.AppendText(nil)
82 }
83
84 // UnmarshalText implements the [encoding.TextUnmarshaler] interface.
85 func (z *Rat) UnmarshalText(text []byte) error {
86 // TODO(gri): get rid of the []byte/string conversion
87 if _, ok := z.SetString([]byte(text)); !ok {
88 return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
89 }
90 return nil
91 }
92