Noticed in an audit that the differeent value renderers perform an expensive and unnecessary string->byteslice in cases where the output write implements io.StringWriter. This change instead invokes io.WriteString(w, formatted) instead of: w.Write([]byte(formatted)) and added benchmarks that show an improvement from just the 1 line change: ```shell $ benchstat before.txt after.txt name old time/op new time/op delta IntValueRendererFormat-8 4.13µs ± 3% 3.95µs ± 6% -4.55% (p=0.000 n=15+14) BytesValueRendererFormat-8 5.22ms ± 3% 4.77ms ± 5% -8.60% (p=0.000 n=15+14) name old alloc/op new alloc/op delta IntValueRendererFormat-8 3.64kB ± 0% 3.31kB ± 0% -9.01% (p=0.000 n=15+15) BytesValueRendererFormat-8 12.6MB ± 0% 8.4MB ± 0% -33.22% (p=0.000 n=15+15) name old allocs/op new allocs/op delta IntValueRendererFormat-8 76.0 ± 0% 67.0 ± 0% -11.84% (p=0.000 n=15+15) BytesValueRendererFormat-8 27.0 ± 0% 18.0 ± 0% -33.33% (p=0.000 n=15+15) ``` While here, implemented negative sign preservation because previously the code wasn't tested for negative values so passing in negative values such as: "-10000000.11" would produce: "10'000'000.11" instead of the proper value with the negative sign preserved: "-10'000'000.11" Fixes #12810 Fixes #12812
35 lines
834 B
Go
35 lines
834 B
Go
package valuerenderer
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"io"
|
|
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
)
|
|
|
|
// bytesValueRenderer implements ValueRenderer for bytes
|
|
type bytesValueRenderer struct {
|
|
}
|
|
|
|
var _ ValueRenderer = bytesValueRenderer{}
|
|
|
|
func (vr bytesValueRenderer) Format(ctx context.Context, v protoreflect.Value, w io.Writer) error {
|
|
_, err := io.WriteString(w, base64.StdEncoding.EncodeToString(v.Bytes()))
|
|
return err
|
|
}
|
|
|
|
func (vr bytesValueRenderer) Parse(_ context.Context, r io.Reader) (protoreflect.Value, error) {
|
|
formatted, err := io.ReadAll(r)
|
|
if err != nil {
|
|
return protoreflect.ValueOfBytes([]byte{}), err
|
|
}
|
|
|
|
data, err := base64.StdEncoding.DecodeString(string(formatted))
|
|
if err != nil {
|
|
return protoreflect.ValueOfBytes([]byte{}), err
|
|
}
|
|
|
|
return protoreflect.ValueOfBytes(data), nil
|
|
}
|