From 36d4b831afa44f4153171218a6930cabcce1c6b1 Mon Sep 17 00:00:00 2001 From: Paul Scott Date: Wed, 26 Feb 2025 11:07:30 +0000 Subject: [PATCH] types/opt: make jsonv2 dependency optional behind ts_omit_jsonv2 tag Updates #TODO Signed-off-by: Paul Scott --- types/opt/value.go | 32 ------------------------------- types/opt/value_jsonv1.go | 34 +++++++++++++++++++++++++++++++++ types/opt/value_jsonv2.go | 40 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 32 deletions(-) create mode 100644 types/opt/value_jsonv1.go create mode 100644 types/opt/value_jsonv2.go diff --git a/types/opt/value.go b/types/opt/value.go index b47b03c81..bd90b5d90 100644 --- a/types/opt/value.go +++ b/types/opt/value.go @@ -6,9 +6,6 @@ package opt import ( "fmt" "reflect" - - jsonv2 "github.com/go-json-experiment/json" - "github.com/go-json-experiment/json/jsontext" ) // Value is an optional value to be JSON-encoded. @@ -99,32 +96,3 @@ func (o Value[T]) Equal(v Value[T]) bool { } return false } - -// MarshalJSONV2 implements [jsonv2.MarshalerV2]. -func (o Value[T]) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error { - if !o.set { - return enc.WriteToken(jsontext.Null) - } - return jsonv2.MarshalEncode(enc, &o.value, opts) -} - -// UnmarshalJSONV2 implements [jsonv2.UnmarshalerV2]. -func (o *Value[T]) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error { - if dec.PeekKind() == 'n' { - *o = Value[T]{} - _, err := dec.ReadToken() // read null - return err - } - o.set = true - return jsonv2.UnmarshalDecode(dec, &o.value, opts) -} - -// MarshalJSON implements [json.Marshaler]. -func (o Value[T]) MarshalJSON() ([]byte, error) { - return jsonv2.Marshal(o) // uses MarshalJSONV2 -} - -// UnmarshalJSON implements [json.Unmarshaler]. -func (o *Value[T]) UnmarshalJSON(b []byte) error { - return jsonv2.Unmarshal(b, o) // uses UnmarshalJSONV2 -} diff --git a/types/opt/value_jsonv1.go b/types/opt/value_jsonv1.go new file mode 100644 index 000000000..886d82468 --- /dev/null +++ b/types/opt/value_jsonv1.go @@ -0,0 +1,34 @@ +//go:build ts_omit_jsonv2 + +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package value + +import ( + "bytes" + "encoding/json" + "fmt" +) + +var null = []byte("null") + +// MarshalJSON implements [json.Marshaler]. +func (o Value[T]) MarshalJSON() ([]byte, error) { + if !o.set { + return null, nil + } + return json.Marshal(o.value) +} + +// UnmarshalJSON implements [json.Unmarshaler]. +func (o *Value[T]) UnmarshalJSON(b []byte) error { + if len(b) > 0 && b[0] == 'n' { + *o = Value[T]{} + if !bytes.Equal(b, null) { + return fmt.Errorf("invalid literal %q, expected %q", b, null) + } + return nil + } + return json.Unmarshal(&o.value, b) +} diff --git a/types/opt/value_jsonv2.go b/types/opt/value_jsonv2.go new file mode 100644 index 000000000..e2e35865e --- /dev/null +++ b/types/opt/value_jsonv2.go @@ -0,0 +1,40 @@ +//go:build !ts_omit_jsonv2 + +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package opt + +import ( + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" +) + +// MarshalJSON implements [json.Marshaler]. +func (o Value[T]) MarshalJSON() ([]byte, error) { + return jsonv2.Marshal(o) // uses MarshalJSONV2 +} + +// UnmarshalJSON implements [json.Unmarshaler]. +func (o *Value[T]) UnmarshalJSON(b []byte) error { + return jsonv2.Unmarshal(b, o) // uses UnmarshalJSONV2 +} + +// MarshalJSONV2 implements [jsonv2.MarshalerV2]. +func (o Value[T]) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error { + if !o.set { + return enc.WriteToken(jsontext.Null) + } + return jsonv2.MarshalEncode(enc, &o.value, opts) +} + +// UnmarshalJSONV2 implements [jsonv2.UnmarshalerV2]. +func (o *Value[T]) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error { + if dec.PeekKind() == 'n' { + *o = Value[T]{} + _, err := dec.ReadToken() // read null + return err + } + o.set = true + return jsonv2.UnmarshalDecode(dec, &o.value, opts) +}