encoding/json/jsontext: expand signature of AppendFormat

The signature of AppendFormat is inconsistent with AppendQuote and AppendUnquote.
Make it support both ~string and ~[]byte as inputs to be consistent.

The AppendXXX functions exists as very low-level functionality for operating
with data that might contain JSON, which may be in a Value, []byte, or string.
Expanding the signature provides for greater calling flexibility.

Performance:
	BenchmarkAppendFormat/FromString-32             14754680                81.46 ns/op            0 B/op          0 allocs/op
	BenchmarkAppendFormat/FromBytes-32              14549612                83.18 ns/op            0 B/op          0 allocs/op

Fixes #79064

Change-Id: Ia0a6526f7111d1183a0eb0c69fcaf3cfb981b532
Reviewed-on: https://go-review.googlesource.com/c/go/+/772820
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
This commit is contained in:
Joe Tsai 2026-04-30 17:07:28 -07:00 committed by Joseph Tsai
parent 60a809d31a
commit 7bb9bc64d0
2 changed files with 33 additions and 2 deletions

View file

@ -42,11 +42,11 @@ func AppendFloat(dst []byte, src float64, bits int) []byte {
//
// The dst and src may overlap.
// If an error is reported, then the entirety of src is appended to dst.
func AppendFormat(dst, src []byte, opts ...Options) ([]byte, error) {
func AppendFormat[Bytes ~[]byte | ~string](dst []byte, src Bytes, opts ...Options) ([]byte, error) {
e := getBufferedEncoder(opts...)
defer putBufferedEncoder(e)
e.s.Flags.Set(jsonflags.OmitTopLevelNewline | 1)
if err := e.s.WriteValue(src); err != nil {
if err := e.s.WriteValue(Value(src)); err != nil {
return append(dst, src...), err
}
return append(dst, e.s.Buf...), nil

View file

@ -198,3 +198,34 @@ func TestValueMethods(t *testing.T) {
})
}
}
func BenchmarkAppendFormat(b *testing.B) {
inputString := `[ null , false , true , "fizzbuzz" , 3.14159 , { "fizz" : "buzz" } ]`
inputBytes := []byte(inputString)
outputWant := `[null,false,true,"fizzbuzz",3.14159,{"fizz":"buzz"}]`
output := make([]byte, 0, len(inputString))
var err error
b.Run("FromString", func(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
if output, err = AppendFormat(output[:0], inputString); err != nil {
b.Fatalf("AppendFormat error: %v", err)
}
}
if string(output) != outputWant {
b.Fatalf("AppendFormat mismatch:\n\tgot: %s\n\twant: %s", output, outputWant)
}
})
b.Run("FromBytes", func(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
if output, err = AppendFormat(output[:0], inputBytes); err != nil {
b.Fatalf("AppendFormat error: %v", err)
}
}
if string(output) != outputWant {
b.Fatalf("AppendFormat mismatch:\n\tgot: %s\n\twant: %s", output, outputWant)
}
})
}