mirror of
https://github.com/golang/go
synced 2024-11-11 17:11:36 -07:00
math/big,regexp: implement the encoding.TextAppender interface
For #62384
This commit is contained in:
parent
2693f77b35
commit
c258d18cce
@ -5,3 +5,7 @@ pkg encoding, type TextAppender interface, AppendText([]uint8) ([]uint8, error)
|
||||
pkg net/url, method (*URL) AppendBinary([]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 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
|
||||
|
1
doc/next/6-stdlib/99-minor/math/big/62384.md
Normal file
1
doc/next/6-stdlib/99-minor/math/big/62384.md
Normal file
@ -0,0 +1 @@
|
||||
[Float], [Int] and [Rat] now implement the [encoding.TextAppender] interface.
|
1
doc/next/6-stdlib/99-minor/regexp/62384.md
Normal file
1
doc/next/6-stdlib/99-minor/regexp/62384.md
Normal file
@ -0,0 +1 @@
|
||||
[Regexp] now implements the [encoding.TextAppender] interface.
|
@ -106,15 +106,21 @@ func (z *Float) GobDecode(buf []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendText implements the [encoding.TextAppender] interface.
|
||||
// Only the [Float] value is marshaled (in full precision), other
|
||||
// attributes such as precision or accuracy are ignored.
|
||||
func (x *Float) AppendText(b []byte) ([]byte, error) {
|
||||
if x == nil {
|
||||
return append(b, "<nil>"...), nil
|
||||
}
|
||||
return x.Append(b, '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) {
|
||||
if x == nil {
|
||||
return []byte("<nil>"), nil
|
||||
}
|
||||
var buf []byte
|
||||
return x.Append(buf, 'g', -1), nil
|
||||
return x.AppendText(nil)
|
||||
}
|
||||
|
||||
// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
|
||||
|
@ -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 {
|
||||
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.
|
||||
func (x *Int) MarshalText() (text []byte, err error) {
|
||||
if x == nil {
|
||||
return []byte("<nil>"), nil
|
||||
}
|
||||
return x.abs.itoa(x.neg, 10), nil
|
||||
return x.AppendText(nil)
|
||||
}
|
||||
|
||||
// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
|
||||
|
@ -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
|
||||
|
||||
// String returns a string representation of x in the form "a/b" (even if b == 1).
|
||||
func (x *Rat) String() string {
|
||||
return string(x.marshal())
|
||||
return string(x.marshal(nil))
|
||||
}
|
||||
|
||||
// marshal implements String returning a slice of bytes
|
||||
func (x *Rat) marshal() []byte {
|
||||
var buf []byte
|
||||
// marshal implements [Rat.String] returning a slice of bytes.
|
||||
// It appends the string representation of x in the form "a/b" (even if b == 1) to buf,
|
||||
// and returns the extended buffer.
|
||||
func (x *Rat) marshal(buf []byte) []byte {
|
||||
buf = x.a.Append(buf, 10)
|
||||
buf = append(buf, '/')
|
||||
if len(x.b.abs) != 0 {
|
||||
|
@ -68,12 +68,17 @@ func (z *Rat) GobDecode(buf []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendText implements the [encoding.TextAppender] interface.
|
||||
func (x *Rat) AppendText(b []byte) ([]byte, error) {
|
||||
if x.IsInt() {
|
||||
return x.a.AppendText(b)
|
||||
}
|
||||
return x.marshal(b), nil
|
||||
}
|
||||
|
||||
// MarshalText implements the [encoding.TextMarshaler] interface.
|
||||
func (x *Rat) MarshalText() (text []byte, err error) {
|
||||
if x.IsInt() {
|
||||
return x.a.MarshalText()
|
||||
}
|
||||
return x.marshal(), nil
|
||||
return x.AppendText(nil)
|
||||
}
|
||||
|
||||
// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
|
||||
|
@ -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) {
|
||||
if unmarshaled.String() != goodRe[i] {
|
||||
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) {
|
||||
re := new(Regexp)
|
||||
|
@ -1277,14 +1277,22 @@ func (re *Regexp) Split(s string, n int) []string {
|
||||
return strings
|
||||
}
|
||||
|
||||
// MarshalText implements [encoding.TextMarshaler]. The output
|
||||
// AppendText implements [encoding.TextAppender]. The output
|
||||
// matches that of calling the [Regexp.String] method.
|
||||
//
|
||||
// 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
|
||||
// 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) {
|
||||
return []byte(re.String()), nil
|
||||
return re.AppendText(nil)
|
||||
}
|
||||
|
||||
// UnmarshalText implements [encoding.TextUnmarshaler] by calling
|
||||
|
Loading…
Reference in New Issue
Block a user