Skip to content
Snippets Groups Projects
Commit 52761076 authored by apocelipes's avatar apocelipes Committed by Gopher Robot
Browse files

math/big,regexp: implement the encoding.TextAppender interface

For #62384

Change-Id: I1557704c6a0f9c6f3b9aad001374dd5cdbc99065
GitHub-Last-Rev: c258d18ccedab5feeb481a2431d5647bde7e5c58
GitHub-Pull-Request: golang/go#68893
Reviewed-on: https://go-review.googlesource.com/c/go/+/605758


Reviewed-by: default avatarIan Lance Taylor <iant@google.com>
Commit-Queue: Robert Griesemer <gri@google.com>
Reviewed-by: default avatarRobert Griesemer <gri@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Robert Griesemer <gri@google.com>
parent bd8977be
No related branches found
No related tags found
No related merge requests found
...@@ -5,3 +5,7 @@ pkg encoding, type TextAppender interface, AppendText([]uint8) ([]uint8, error) ...@@ -5,3 +5,7 @@ pkg encoding, type TextAppender interface, AppendText([]uint8) ([]uint8, error)
pkg net/url, method (*URL) AppendBinary([]uint8) ([]uint8, error) #62384 pkg net/url, method (*URL) AppendBinary([]uint8) ([]uint8, error) #62384
pkg log/slog, method (Level) AppendText([]uint8) ([]uint8, error) #62384 pkg log/slog, method (Level) AppendText([]uint8) ([]uint8, error) #62384
pkg log/slog, method (*LevelVar) AppendText([]uint8) ([]uint8, error) #62384 pkg log/slog, method (*LevelVar) AppendText([]uint8) ([]uint8, error) #62384
pkg math/big, method (*Float) AppendText([]uint8) ([]uint8, error) #62384
pkg math/big, method (*Int) AppendText([]uint8) ([]uint8, error) #62384
pkg math/big, method (*Rat) AppendText([]uint8) ([]uint8, error) #62384
pkg regexp, method (*Regexp) AppendText([]uint8) ([]uint8, error) #62384
[Float], [Int] and [Rat] now implement the [encoding.TextAppender] interface.
[Regexp] now implements the [encoding.TextAppender] interface.
...@@ -106,15 +106,21 @@ func (z *Float) GobDecode(buf []byte) error { ...@@ -106,15 +106,21 @@ func (z *Float) GobDecode(buf []byte) error {
return nil return nil
} }
// MarshalText implements the [encoding.TextMarshaler] interface. // AppendText implements the [encoding.TextAppender] interface.
// Only the [Float] value is marshaled (in full precision), other // Only the [Float] value is marshaled (in full precision), other
// attributes such as precision or accuracy are ignored. // attributes such as precision or accuracy are ignored.
func (x *Float) MarshalText() (text []byte, err error) { func (x *Float) AppendText(b []byte) ([]byte, error) {
if x == nil { if x == nil {
return []byte("<nil>"), nil return append(b, "<nil>"...), nil
} }
var buf []byte return x.Append(b, 'g', -1), nil
return x.Append(buf, 'g', -1), nil }
// MarshalText implements the [encoding.TextMarshaler] interface.
// Only the [Float] value is marshaled (in full precision), other
// attributes such as precision or accuracy are ignored.
func (x *Float) MarshalText() (text []byte, err error) {
return x.AppendText(nil)
} }
// UnmarshalText implements the [encoding.TextUnmarshaler] interface. // UnmarshalText implements the [encoding.TextUnmarshaler] interface.
......
...@@ -171,3 +171,46 @@ func TestFloatGobDecodeInvalid(t *testing.T) { ...@@ -171,3 +171,46 @@ func TestFloatGobDecodeInvalid(t *testing.T) {
} }
} }
} }
func TestFloatAppendText(t *testing.T) {
for _, test := range floatVals {
for _, sign := range []string{"", "+", "-"} {
for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} {
if prec > 53 && testing.Short() {
continue
}
x := sign + test
var tx Float
_, _, err := tx.SetPrec(prec).Parse(x, 0)
if err != nil {
t.Errorf("parsing of %s (prec = %d) failed (invalid test case): %v", x, prec, err)
continue
}
buf := make([]byte, 4, 32)
b, err := tx.AppendText(buf)
if err != nil {
t.Errorf("marshaling of %v (prec = %d) failed: %v", &tx, prec, err)
continue
}
var rx Float
rx.SetPrec(prec)
if err := rx.UnmarshalText(b[4:]); err != nil {
t.Errorf("unmarshaling of %v (prec = %d) failed: %v", &tx, prec, err)
continue
}
if rx.Cmp(&tx) != 0 {
t.Errorf("AppendText of %v (prec = %d) failed: got %v want %v", &tx, prec, &rx, &tx)
}
}
}
}
}
func TestFloatAppendTextNil(t *testing.T) {
var x *Float
buf := make([]byte, 4, 16)
data, _ := x.AppendText(buf)
if string(data[4:]) != "<nil>" {
t.Errorf("got %q, want <nil>", data[4:])
}
}
...@@ -45,12 +45,14 @@ func (z *Int) GobDecode(buf []byte) error { ...@@ -45,12 +45,14 @@ func (z *Int) GobDecode(buf []byte) error {
return nil return nil
} }
// AppendText implements the [encoding.TextAppender] interface.
func (x *Int) AppendText(b []byte) (text []byte, err error) {
return x.Append(b, 10), nil
}
// MarshalText implements the [encoding.TextMarshaler] interface. // MarshalText implements the [encoding.TextMarshaler] interface.
func (x *Int) MarshalText() (text []byte, err error) { func (x *Int) MarshalText() (text []byte, err error) {
if x == nil { return x.AppendText(nil)
return []byte("<nil>"), nil
}
return x.abs.itoa(x.neg, 10), nil
} }
// UnmarshalText implements the [encoding.TextUnmarshaler] interface. // UnmarshalText implements the [encoding.TextUnmarshaler] interface.
......
...@@ -132,3 +132,36 @@ func TestIntXMLEncoding(t *testing.T) { ...@@ -132,3 +132,36 @@ func TestIntXMLEncoding(t *testing.T) {
} }
} }
} }
func TestIntAppendText(t *testing.T) {
for _, test := range encodingTests {
for _, sign := range []string{"", "+", "-"} {
x := sign + test
var tx Int
tx.SetString(x, 10)
buf := make([]byte, 4, 32)
b, err := tx.AppendText(buf)
if err != nil {
t.Errorf("marshaling of %s failed: %s", &tx, err)
continue
}
var rx Int
if err := rx.UnmarshalText(b[4:]); err != nil {
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
continue
}
if rx.Cmp(&tx) != 0 {
t.Errorf("AppendText of %s failed: got %s want %s", &tx, &rx, &tx)
}
}
}
}
func TestIntAppendTextNil(t *testing.T) {
var x *Int
buf := make([]byte, 4, 16)
data, _ := x.AppendText(buf)
if string(data[4:]) != "<nil>" {
t.Errorf("got %q, want <nil>", data[4:])
}
}
...@@ -299,12 +299,13 @@ func scanExponent(r io.ByteScanner, base2ok, sepOk bool) (exp int64, base int, e ...@@ -299,12 +299,13 @@ func scanExponent(r io.ByteScanner, base2ok, sepOk bool) (exp int64, base int, e
// String returns a string representation of x in the form "a/b" (even if b == 1). // String returns a string representation of x in the form "a/b" (even if b == 1).
func (x *Rat) String() string { func (x *Rat) String() string {
return string(x.marshal()) return string(x.marshal(nil))
} }
// marshal implements String returning a slice of bytes // marshal implements [Rat.String] returning a slice of bytes.
func (x *Rat) marshal() []byte { // It appends the string representation of x in the form "a/b" (even if b == 1) to buf,
var buf []byte // and returns the extended buffer.
func (x *Rat) marshal(buf []byte) []byte {
buf = x.a.Append(buf, 10) buf = x.a.Append(buf, 10)
buf = append(buf, '/') buf = append(buf, '/')
if len(x.b.abs) != 0 { if len(x.b.abs) != 0 {
......
...@@ -68,12 +68,17 @@ func (z *Rat) GobDecode(buf []byte) error { ...@@ -68,12 +68,17 @@ func (z *Rat) GobDecode(buf []byte) error {
return nil return nil
} }
// MarshalText implements the [encoding.TextMarshaler] interface. // AppendText implements the [encoding.TextAppender] interface.
func (x *Rat) MarshalText() (text []byte, err error) { func (x *Rat) AppendText(b []byte) ([]byte, error) {
if x.IsInt() { if x.IsInt() {
return x.a.MarshalText() return x.a.AppendText(b)
} }
return x.marshal(), nil return x.marshal(b), nil
}
// MarshalText implements the [encoding.TextMarshaler] interface.
func (x *Rat) MarshalText() (text []byte, err error) {
return x.AppendText(nil)
} }
// UnmarshalText implements the [encoding.TextUnmarshaler] interface. // UnmarshalText implements the [encoding.TextUnmarshaler] interface.
......
...@@ -136,3 +136,26 @@ func TestRatGobDecodeShortBuffer(t *testing.T) { ...@@ -136,3 +136,26 @@ func TestRatGobDecodeShortBuffer(t *testing.T) {
} }
} }
} }
func TestRatAppendText(t *testing.T) {
for _, num := range ratNums {
for _, denom := range ratDenoms {
var tx Rat
tx.SetString(num + "/" + denom)
buf := make([]byte, 4, 32)
b, err := tx.AppendText(buf)
if err != nil {
t.Errorf("marshaling of %s failed: %s", &tx, err)
continue
}
var rx Rat
if err := rx.UnmarshalText(b[4:]); err != nil {
t.Errorf("unmarshaling of %s failed: %s", &tx, err)
continue
}
if rx.Cmp(&tx) != 0 {
t.Errorf("AppendText of %s failed: got %s want %s", &tx, &rx, &tx)
}
}
}
}
...@@ -965,6 +965,21 @@ func TestUnmarshalText(t *testing.T) { ...@@ -965,6 +965,21 @@ func TestUnmarshalText(t *testing.T) {
if unmarshaled.String() != goodRe[i] { if unmarshaled.String() != goodRe[i] {
t.Errorf("UnmarshalText returned unexpected value: %s", unmarshaled.String()) t.Errorf("UnmarshalText returned unexpected value: %s", unmarshaled.String())
} }
buf := make([]byte, 4, 32)
marshalAppend, err := re.AppendText(buf)
if err != nil {
t.Errorf("regexp %#q failed to marshal: %s", re, err)
continue
}
marshalAppend = marshalAppend[4:]
if err := unmarshaled.UnmarshalText(marshalAppend); err != nil {
t.Errorf("regexp %#q failed to unmarshal: %s", re, err)
continue
}
if unmarshaled.String() != goodRe[i] {
t.Errorf("UnmarshalText returned unexpected value: %s", unmarshaled.String())
}
} }
t.Run("invalid pattern", func(t *testing.T) { t.Run("invalid pattern", func(t *testing.T) {
re := new(Regexp) re := new(Regexp)
......
...@@ -1277,14 +1277,22 @@ func (re *Regexp) Split(s string, n int) []string { ...@@ -1277,14 +1277,22 @@ func (re *Regexp) Split(s string, n int) []string {
return strings return strings
} }
// MarshalText implements [encoding.TextMarshaler]. The output // AppendText implements [encoding.TextAppender]. The output
// matches that of calling the [Regexp.String] method. // matches that of calling the [Regexp.String] method.
// //
// Note that the output is lossy in some cases: This method does not indicate // Note that the output is lossy in some cases: This method does not indicate
// POSIX regular expressions (i.e. those compiled by calling [CompilePOSIX]), or // POSIX regular expressions (i.e. those compiled by calling [CompilePOSIX]), or
// those for which the [Regexp.Longest] method has been called. // those for which the [Regexp.Longest] method has been called.
func (re *Regexp) AppendText(b []byte) ([]byte, error) {
return append(b, re.String()...), nil
}
// MarshalText implements [encoding.TextMarshaler]. The output
// matches that of calling the [Regexp.AppendText] method.
//
// See [Regexp.AppendText] for more information.
func (re *Regexp) MarshalText() ([]byte, error) { func (re *Regexp) MarshalText() ([]byte, error) {
return []byte(re.String()), nil return re.AppendText(nil)
} }
// UnmarshalText implements [encoding.TextUnmarshaler] by calling // UnmarshalText implements [encoding.TextUnmarshaler] by calling
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment