summaryrefslogtreecommitdiffhomepage
path: root/util/jsonutil
diff options
context:
space:
mode:
authorNick Khyl <nickk@tailscale.com>2024-12-05 13:16:48 -0600
committerNick Khyl <nickk@tailscale.com>2024-12-05 13:16:48 -0600
commit0267fe83b200f1702a2fa0a395442c02a053fadb (patch)
tree63654c55225eeb834de59a5a0bc8d19033c6145b /util/jsonutil
parent87546a5edf6b6503a87eeb2d666baba57398a066 (diff)
downloadtailscale-1.78.0.tar.xz
tailscale-1.78.0.zip
VERSION.txt: this is v1.78.0v1.78.0
Signed-off-by: Nick Khyl <nickk@tailscale.com>
Diffstat (limited to 'util/jsonutil')
-rw-r--r--util/jsonutil/types.go32
-rw-r--r--util/jsonutil/unmarshal.go178
2 files changed, 105 insertions, 105 deletions
diff --git a/util/jsonutil/types.go b/util/jsonutil/types.go
index 057473249..2ee53f44a 100644
--- a/util/jsonutil/types.go
+++ b/util/jsonutil/types.go
@@ -1,16 +1,16 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package jsonutil
-
-// Bytes is a byte slice in a json-encoded struct.
-// encoding/json assumes that []byte fields are hex-encoded.
-// Bytes are not hex-encoded; they are treated the same as strings.
-// This can avoid unnecessary allocations due to a round trip through strings.
-type Bytes []byte
-
-func (b *Bytes) UnmarshalText(text []byte) error {
- // Copy the contexts of text.
- *b = append(*b, text...)
- return nil
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package jsonutil
+
+// Bytes is a byte slice in a json-encoded struct.
+// encoding/json assumes that []byte fields are hex-encoded.
+// Bytes are not hex-encoded; they are treated the same as strings.
+// This can avoid unnecessary allocations due to a round trip through strings.
+type Bytes []byte
+
+func (b *Bytes) UnmarshalText(text []byte) error {
+ // Copy the contexts of text.
+ *b = append(*b, text...)
+ return nil
+}
diff --git a/util/jsonutil/unmarshal.go b/util/jsonutil/unmarshal.go
index b1eb4ea87..13aea0c87 100644
--- a/util/jsonutil/unmarshal.go
+++ b/util/jsonutil/unmarshal.go
@@ -1,89 +1,89 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-// Package jsonutil provides utilities to improve JSON performance.
-// It includes an Unmarshal wrapper that amortizes allocated garbage over subsequent runs
-// and a Bytes type to reduce allocations when unmarshalling a non-hex-encoded string into a []byte.
-package jsonutil
-
-import (
- "bytes"
- "encoding/json"
- "sync"
-)
-
-// decoder is a re-usable json decoder.
-type decoder struct {
- dec *json.Decoder
- r *bytes.Reader
-}
-
-var readerPool = sync.Pool{
- New: func() any {
- return bytes.NewReader(nil)
- },
-}
-
-var decoderPool = sync.Pool{
- New: func() any {
- var d decoder
- d.r = readerPool.Get().(*bytes.Reader)
- d.dec = json.NewDecoder(d.r)
- return &d
- },
-}
-
-// Unmarshal is similar to encoding/json.Unmarshal.
-// There are three major differences:
-//
-// On error, encoding/json.Unmarshal zeros v.
-// This Unmarshal may leave partial data in v.
-// Always check the error before using v!
-// (Future improvements may remove this bug.)
-//
-// The errors they return don't always match perfectly.
-// If you do error matching more precise than err != nil,
-// don't use this Unmarshal.
-//
-// This Unmarshal allocates considerably less memory.
-func Unmarshal(b []byte, v any) error {
- d := decoderPool.Get().(*decoder)
- d.r.Reset(b)
- off := d.dec.InputOffset()
- err := d.dec.Decode(v)
- d.r.Reset(nil) // don't keep a reference to b
- // In case of error, report the offset in this byte slice,
- // instead of in the totality of all bytes this decoder has processed.
- // It is not possible to make all errors match json.Unmarshal exactly,
- // but we can at least try.
- switch jsonerr := err.(type) {
- case *json.SyntaxError:
- jsonerr.Offset -= off
- case *json.UnmarshalTypeError:
- jsonerr.Offset -= off
- case nil:
- // json.Unmarshal fails if there's any extra junk in the input.
- // json.Decoder does not; see https://github.com/golang/go/issues/36225.
- // We need to check for anything left over in the buffer.
- if d.dec.More() {
- // TODO: Provide a better error message.
- // Unfortunately, we can't set the msg field.
- // The offset doesn't perfectly match json:
- // Ours is at the end of the valid data,
- // and theirs is at the beginning of the extra data after whitespace.
- // Close enough, though.
- err = &json.SyntaxError{Offset: d.dec.InputOffset() - off}
-
- // TODO: zero v. This is hard; see encoding/json.indirect.
- }
- }
- if err == nil {
- decoderPool.Put(d)
- } else {
- // There might be junk left in the decoder's buffer.
- // There's no way to flush it, no Reset method.
- // Abandoned the decoder but reuse the reader.
- readerPool.Put(d.r)
- }
- return err
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Package jsonutil provides utilities to improve JSON performance.
+// It includes an Unmarshal wrapper that amortizes allocated garbage over subsequent runs
+// and a Bytes type to reduce allocations when unmarshalling a non-hex-encoded string into a []byte.
+package jsonutil
+
+import (
+ "bytes"
+ "encoding/json"
+ "sync"
+)
+
+// decoder is a re-usable json decoder.
+type decoder struct {
+ dec *json.Decoder
+ r *bytes.Reader
+}
+
+var readerPool = sync.Pool{
+ New: func() any {
+ return bytes.NewReader(nil)
+ },
+}
+
+var decoderPool = sync.Pool{
+ New: func() any {
+ var d decoder
+ d.r = readerPool.Get().(*bytes.Reader)
+ d.dec = json.NewDecoder(d.r)
+ return &d
+ },
+}
+
+// Unmarshal is similar to encoding/json.Unmarshal.
+// There are three major differences:
+//
+// On error, encoding/json.Unmarshal zeros v.
+// This Unmarshal may leave partial data in v.
+// Always check the error before using v!
+// (Future improvements may remove this bug.)
+//
+// The errors they return don't always match perfectly.
+// If you do error matching more precise than err != nil,
+// don't use this Unmarshal.
+//
+// This Unmarshal allocates considerably less memory.
+func Unmarshal(b []byte, v any) error {
+ d := decoderPool.Get().(*decoder)
+ d.r.Reset(b)
+ off := d.dec.InputOffset()
+ err := d.dec.Decode(v)
+ d.r.Reset(nil) // don't keep a reference to b
+ // In case of error, report the offset in this byte slice,
+ // instead of in the totality of all bytes this decoder has processed.
+ // It is not possible to make all errors match json.Unmarshal exactly,
+ // but we can at least try.
+ switch jsonerr := err.(type) {
+ case *json.SyntaxError:
+ jsonerr.Offset -= off
+ case *json.UnmarshalTypeError:
+ jsonerr.Offset -= off
+ case nil:
+ // json.Unmarshal fails if there's any extra junk in the input.
+ // json.Decoder does not; see https://github.com/golang/go/issues/36225.
+ // We need to check for anything left over in the buffer.
+ if d.dec.More() {
+ // TODO: Provide a better error message.
+ // Unfortunately, we can't set the msg field.
+ // The offset doesn't perfectly match json:
+ // Ours is at the end of the valid data,
+ // and theirs is at the beginning of the extra data after whitespace.
+ // Close enough, though.
+ err = &json.SyntaxError{Offset: d.dec.InputOffset() - off}
+
+ // TODO: zero v. This is hard; see encoding/json.indirect.
+ }
+ }
+ if err == nil {
+ decoderPool.Put(d)
+ } else {
+ // There might be junk left in the decoder's buffer.
+ // There's no way to flush it, no Reset method.
+ // Abandoned the decoder but reuse the reader.
+ readerPool.Put(d.r)
+ }
+ return err
+}