diff --git a/cmd/cloner/cloner.go b/cmd/cloner/cloner.go index a1ffc30fe..15a808141 100644 --- a/cmd/cloner/cloner.go +++ b/cmd/cloner/cloner.go @@ -136,13 +136,13 @@ func gen(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named) { writef("if src.%s[i] == nil { dst.%s[i] = nil } else {", fname, fname) if codegen.ContainsPointers(ptr.Elem()) { if _, isIface := ptr.Elem().Underlying().(*types.Interface); isIface { - it.Import("tailscale.com/types/ptr") + it.Import("", "tailscale.com/types/ptr") writef("\tdst.%s[i] = ptr.To((*src.%s[i]).Clone())", fname, fname) } else { writef("\tdst.%s[i] = src.%s[i].Clone()", fname, fname) } } else { - it.Import("tailscale.com/types/ptr") + it.Import("", "tailscale.com/types/ptr") writef("\tdst.%s[i] = ptr.To(*src.%s[i])", fname, fname) } writef("}") @@ -165,7 +165,7 @@ func gen(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named) { writef("dst.%s = src.%s.Clone()", fname, fname) continue } - it.Import("tailscale.com/types/ptr") + it.Import("", "tailscale.com/types/ptr") writef("if dst.%s != nil {", fname) if _, isIface := base.Underlying().(*types.Interface); isIface && hasPtrs { writef("\tdst.%s = ptr.To((*src.%s).Clone())", fname, fname) @@ -197,13 +197,13 @@ func gen(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named) { writef("\t\tif v == nil { dst.%s[k] = nil } else {", fname) if base := elem.Elem().Underlying(); codegen.ContainsPointers(base) { if _, isIface := base.(*types.Interface); isIface { - it.Import("tailscale.com/types/ptr") + it.Import("", "tailscale.com/types/ptr") writef("\t\t\tdst.%s[k] = ptr.To((*v).Clone())", fname) } else { writef("\t\t\tdst.%s[k] = v.Clone()", fname) } } else { - it.Import("tailscale.com/types/ptr") + it.Import("", "tailscale.com/types/ptr") writef("\t\t\tdst.%s[k] = ptr.To(*v)", fname) } writef("}") @@ -224,7 +224,7 @@ func gen(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named) { writef("\t}") writef("}") } else { - it.Import("maps") + it.Import("", "maps") writef("\tdst.%s = maps.Clone(src.%s)", fname, fname) } case *types.Interface: diff --git a/cmd/stund/depaware.txt b/cmd/stund/depaware.txt index d389d59a3..8e4db75ae 100644 --- a/cmd/stund/depaware.txt +++ b/cmd/stund/depaware.txt @@ -2,7 +2,7 @@ tailscale.com/cmd/stund dependencies: (generated by github.com/tailscale/depawar github.com/beorn7/perks/quantile from github.com/prometheus/client_golang/prometheus 💣 github.com/cespare/xxhash/v2 from github.com/prometheus/client_golang/prometheus - github.com/go-json-experiment/json from tailscale.com/types/opt + github.com/go-json-experiment/json from tailscale.com/types/opt+ github.com/go-json-experiment/json/internal from github.com/go-json-experiment/json+ github.com/go-json-experiment/json/internal/jsonflags from github.com/go-json-experiment/json+ github.com/go-json-experiment/json/internal/jsonopts from github.com/go-json-experiment/json+ diff --git a/cmd/viewer/tests/tests_view.go b/cmd/viewer/tests/tests_view.go index f1d8f424f..bc95fea01 100644 --- a/cmd/viewer/tests/tests_view.go +++ b/cmd/viewer/tests/tests_view.go @@ -6,10 +6,12 @@ package tests import ( - "encoding/json" + jsonv1 "encoding/json" "errors" "net/netip" + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "golang.org/x/exp/constraints" "tailscale.com/types/views" ) @@ -44,8 +46,17 @@ func (v StructWithPtrsView) AsStruct() *StructWithPtrs { return v.ж.Clone() } -func (v StructWithPtrsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v StructWithPtrsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v StructWithPtrsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *StructWithPtrsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -54,7 +65,20 @@ func (v *StructWithPtrsView) UnmarshalJSON(b []byte) error { return nil } var x StructWithPtrs - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *StructWithPtrsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x StructWithPtrs + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -108,8 +132,17 @@ func (v StructWithoutPtrsView) AsStruct() *StructWithoutPtrs { return v.ж.Clone() } -func (v StructWithoutPtrsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v StructWithoutPtrsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v StructWithoutPtrsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *StructWithoutPtrsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -118,7 +151,20 @@ func (v *StructWithoutPtrsView) UnmarshalJSON(b []byte) error { return nil } var x StructWithoutPtrs - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *StructWithoutPtrsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x StructWithoutPtrs + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -162,8 +208,17 @@ func (v MapView) AsStruct() *Map { return v.ж.Clone() } -func (v MapView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v MapView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v MapView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *MapView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -172,7 +227,20 @@ func (v *MapView) UnmarshalJSON(b []byte) error { return nil } var x Map - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *MapView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Map + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -268,8 +336,17 @@ func (v StructWithSlicesView) AsStruct() *StructWithSlices { return v.ж.Clone() } -func (v StructWithSlicesView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v StructWithSlicesView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v StructWithSlicesView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *StructWithSlicesView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -278,7 +355,20 @@ func (v *StructWithSlicesView) UnmarshalJSON(b []byte) error { return nil } var x StructWithSlices - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *StructWithSlicesView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x StructWithSlices + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -342,8 +432,17 @@ func (v StructWithEmbeddedView) AsStruct() *StructWithEmbedded { return v.ж.Clone() } -func (v StructWithEmbeddedView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v StructWithEmbeddedView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v StructWithEmbeddedView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *StructWithEmbeddedView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -352,7 +451,20 @@ func (v *StructWithEmbeddedView) UnmarshalJSON(b []byte) error { return nil } var x StructWithEmbedded - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *StructWithEmbeddedView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x StructWithEmbedded + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -398,8 +510,17 @@ func (v GenericIntStructView[T]) AsStruct() *GenericIntStruct[T] { return v.ж.Clone() } -func (v GenericIntStructView[T]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v GenericIntStructView[T]) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v GenericIntStructView[T]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *GenericIntStructView[T]) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -408,7 +529,20 @@ func (v *GenericIntStructView[T]) UnmarshalJSON(b []byte) error { return nil } var x GenericIntStruct[T] - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *GenericIntStructView[T]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x GenericIntStruct[T] + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -470,8 +604,17 @@ func (v GenericNoPtrsStructView[T]) AsStruct() *GenericNoPtrsStruct[T] { return v.ж.Clone() } -func (v GenericNoPtrsStructView[T]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v GenericNoPtrsStructView[T]) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v GenericNoPtrsStructView[T]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *GenericNoPtrsStructView[T]) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -480,7 +623,20 @@ func (v *GenericNoPtrsStructView[T]) UnmarshalJSON(b []byte) error { return nil } var x GenericNoPtrsStruct[T] - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *GenericNoPtrsStructView[T]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x GenericNoPtrsStruct[T] + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -542,8 +698,17 @@ func (v GenericCloneableStructView[T, V]) AsStruct() *GenericCloneableStruct[T, return v.ж.Clone() } -func (v GenericCloneableStructView[T, V]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v GenericCloneableStructView[T, V]) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v GenericCloneableStructView[T, V]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *GenericCloneableStructView[T, V]) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -552,7 +717,20 @@ func (v *GenericCloneableStructView[T, V]) UnmarshalJSON(b []byte) error { return nil } var x GenericCloneableStruct[T, V] - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *GenericCloneableStructView[T, V]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x GenericCloneableStruct[T, V] + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -617,8 +795,17 @@ func (v StructWithContainersView) AsStruct() *StructWithContainers { return v.ж.Clone() } -func (v StructWithContainersView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v StructWithContainersView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v StructWithContainersView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *StructWithContainersView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -627,7 +814,20 @@ func (v *StructWithContainersView) UnmarshalJSON(b []byte) error { return nil } var x StructWithContainers - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *StructWithContainersView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x StructWithContainers + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -689,8 +889,17 @@ func (v StructWithTypeAliasFieldsView) AsStruct() *StructWithTypeAliasFields { return v.ж.Clone() } -func (v StructWithTypeAliasFieldsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v StructWithTypeAliasFieldsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v StructWithTypeAliasFieldsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *StructWithTypeAliasFieldsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -699,7 +908,20 @@ func (v *StructWithTypeAliasFieldsView) UnmarshalJSON(b []byte) error { return nil } var x StructWithTypeAliasFields - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *StructWithTypeAliasFieldsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x StructWithTypeAliasFields + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -787,10 +1009,17 @@ func (v GenericTypeAliasStructView[T, T2, V2]) AsStruct() *GenericTypeAliasStruc return v.ж.Clone() } +// MarshalJSON implements [jsonv1.Marshaler]. func (v GenericTypeAliasStructView[T, T2, V2]) MarshalJSON() ([]byte, error) { - return json.Marshal(v.ж) + return jsonv1.Marshal(v.ж) } +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v GenericTypeAliasStructView[T, T2, V2]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *GenericTypeAliasStructView[T, T2, V2]) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -799,7 +1028,20 @@ func (v *GenericTypeAliasStructView[T, T2, V2]) UnmarshalJSON(b []byte) error { return nil } var x GenericTypeAliasStruct[T, T2, V2] - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *GenericTypeAliasStructView[T, T2, V2]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x GenericTypeAliasStruct[T, T2, V2] + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x diff --git a/cmd/viewer/viewer.go b/cmd/viewer/viewer.go index 2d30cc2eb..a9617ac10 100644 --- a/cmd/viewer/viewer.go +++ b/cmd/viewer/viewer.go @@ -49,8 +49,17 @@ func (v {{.ViewName}}{{.TypeParamNames}}) AsStruct() *{{.StructName}}{{.TypePara return v.ж.Clone() } -func (v {{.ViewName}}{{.TypeParamNames}}) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v {{.ViewName}}{{.TypeParamNames}}) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v {{.ViewName}}{{.TypeParamNames}}) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *{{.ViewName}}{{.TypeParamNames}}) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -59,10 +68,23 @@ func (v *{{.ViewName}}{{.TypeParamNames}}) UnmarshalJSON(b []byte) error { return nil } var x {{.StructName}}{{.TypeParamNames}} - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *{{.ViewName}}{{.TypeParamNames}}) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x {{.StructName}}{{.TypeParamNames}} + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } - v.ж=&x + v.ж = &x return nil } @@ -125,8 +147,10 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, _ * if !ok || codegen.IsViewType(t) { return } - it.Import("encoding/json") - it.Import("errors") + it.Import("jsonv1", "encoding/json") + it.Import("jsonv2", "github.com/go-json-experiment/json") + it.Import("", "github.com/go-json-experiment/json/jsontext") + it.Import("", "errors") args := struct { StructName string @@ -182,11 +206,11 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, _ * switch elem.String() { case "byte": args.FieldType = it.QualifiedName(fieldType) - it.Import("tailscale.com/types/views") + it.Import("", "tailscale.com/types/views") writeTemplate("byteSliceField") default: args.FieldType = it.QualifiedName(elem) - it.Import("tailscale.com/types/views") + it.Import("", "tailscale.com/types/views") shallow, deep, base := requiresCloning(elem) if deep { switch elem.Underlying().(type) { @@ -252,7 +276,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, _ * writeTemplate("unsupportedField") continue } - it.Import("tailscale.com/types/views") + it.Import("", "tailscale.com/types/views") args.MapKeyType = it.QualifiedName(key) mElem := m.Elem() var template string diff --git a/cmd/viewer/viewer_test.go b/cmd/viewer/viewer_test.go index cd5f3d95f..d12d49655 100644 --- a/cmd/viewer/viewer_test.go +++ b/cmd/viewer/viewer_test.go @@ -20,19 +20,19 @@ func TestViewerImports(t *testing.T) { name string content string typeNames []string - wantImports []string + wantImports [][2]string }{ { name: "Map", content: `type Test struct { Map map[string]int }`, typeNames: []string{"Test"}, - wantImports: []string{"tailscale.com/types/views"}, + wantImports: [][2]string{{"", "tailscale.com/types/views"}}, }, { name: "Slice", content: `type Test struct { Slice []int }`, typeNames: []string{"Test"}, - wantImports: []string{"tailscale.com/types/views"}, + wantImports: [][2]string{{"", "tailscale.com/types/views"}}, }, } for _, tt := range tests { @@ -68,9 +68,9 @@ func TestViewerImports(t *testing.T) { genView(&output, tracker, namedType, pkg) } - for _, pkgName := range tt.wantImports { - if !tracker.Has(pkgName) { - t.Errorf("missing import %q", pkgName) + for _, pkg := range tt.wantImports { + if !tracker.Has(pkg[0], pkg[1]) { + t.Errorf("missing import %q", pkg) } } }) diff --git a/drive/drive_view.go b/drive/drive_view.go index 0f6686f24..6338705a6 100644 --- a/drive/drive_view.go +++ b/drive/drive_view.go @@ -6,9 +6,11 @@ package drive import ( - "encoding/json" + jsonv1 "encoding/json" "errors" + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "tailscale.com/types/views" ) @@ -42,8 +44,17 @@ func (v ShareView) AsStruct() *Share { return v.ж.Clone() } -func (v ShareView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v ShareView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v ShareView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *ShareView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -52,7 +63,20 @@ func (v *ShareView) UnmarshalJSON(b []byte) error { return nil } var x Share - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *ShareView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Share + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x diff --git a/go.mod b/go.mod index 28b2a764f..fba5a4f54 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/frankban/quicktest v1.14.6 github.com/fxamacker/cbor/v2 v2.7.0 github.com/gaissmai/bart v0.18.0 - github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 + github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced github.com/go-logr/zapr v1.3.0 github.com/go-ole/go-ole v1.3.0 github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 diff --git a/go.sum b/go.sum index 23ca2dc9b..df5d27313 100644 --- a/go.sum +++ b/go.sum @@ -345,8 +345,8 @@ github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0q github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY= -github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= +github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I= +github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= diff --git a/ipn/ipn_view.go b/ipn/ipn_view.go index 1d31ced9d..0f0f652d1 100644 --- a/ipn/ipn_view.go +++ b/ipn/ipn_view.go @@ -6,10 +6,12 @@ package ipn import ( - "encoding/json" + jsonv1 "encoding/json" "errors" "net/netip" + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "tailscale.com/drive" "tailscale.com/tailcfg" "tailscale.com/types/opt" @@ -48,8 +50,17 @@ func (v LoginProfileView) AsStruct() *LoginProfile { return v.ж.Clone() } -func (v LoginProfileView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v LoginProfileView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v LoginProfileView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *LoginProfileView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -58,7 +69,20 @@ func (v *LoginProfileView) UnmarshalJSON(b []byte) error { return nil } var x LoginProfile - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *LoginProfileView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x LoginProfile + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -114,8 +138,17 @@ func (v PrefsView) AsStruct() *Prefs { return v.ж.Clone() } -func (v PrefsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v PrefsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v PrefsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *PrefsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -124,7 +157,20 @@ func (v *PrefsView) UnmarshalJSON(b []byte) error { return nil } var x Prefs - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *PrefsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Prefs + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -239,8 +285,17 @@ func (v ServeConfigView) AsStruct() *ServeConfig { return v.ж.Clone() } -func (v ServeConfigView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v ServeConfigView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v ServeConfigView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *ServeConfigView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -249,7 +304,20 @@ func (v *ServeConfigView) UnmarshalJSON(b []byte) error { return nil } var x ServeConfig - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *ServeConfigView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x ServeConfig + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -323,8 +391,17 @@ func (v ServiceConfigView) AsStruct() *ServiceConfig { return v.ж.Clone() } -func (v ServiceConfigView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v ServiceConfigView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v ServiceConfigView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *ServiceConfigView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -333,7 +410,20 @@ func (v *ServiceConfigView) UnmarshalJSON(b []byte) error { return nil } var x ServiceConfig - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *ServiceConfigView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x ServiceConfig + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -388,8 +478,17 @@ func (v TCPPortHandlerView) AsStruct() *TCPPortHandler { return v.ж.Clone() } -func (v TCPPortHandlerView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v TCPPortHandlerView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v TCPPortHandlerView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *TCPPortHandlerView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -398,7 +497,20 @@ func (v *TCPPortHandlerView) UnmarshalJSON(b []byte) error { return nil } var x TCPPortHandler - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *TCPPortHandlerView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x TCPPortHandler + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -446,8 +558,17 @@ func (v HTTPHandlerView) AsStruct() *HTTPHandler { return v.ж.Clone() } -func (v HTTPHandlerView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v HTTPHandlerView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v HTTPHandlerView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *HTTPHandlerView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -456,7 +577,20 @@ func (v *HTTPHandlerView) UnmarshalJSON(b []byte) error { return nil } var x HTTPHandler - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *HTTPHandlerView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x HTTPHandler + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -502,8 +636,17 @@ func (v WebServerConfigView) AsStruct() *WebServerConfig { return v.ж.Clone() } -func (v WebServerConfigView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v WebServerConfigView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v WebServerConfigView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *WebServerConfigView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -512,7 +655,20 @@ func (v *WebServerConfigView) UnmarshalJSON(b []byte) error { return nil } var x WebServerConfig - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *WebServerConfigView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x WebServerConfig + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x diff --git a/tailcfg/tailcfg_view.go b/tailcfg/tailcfg_view.go index c40780021..8dc4f1ca8 100644 --- a/tailcfg/tailcfg_view.go +++ b/tailcfg/tailcfg_view.go @@ -6,11 +6,13 @@ package tailcfg import ( - "encoding/json" + jsonv1 "encoding/json" "errors" "net/netip" "time" + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "tailscale.com/types/dnstype" "tailscale.com/types/key" "tailscale.com/types/opt" @@ -49,8 +51,17 @@ func (v UserView) AsStruct() *User { return v.ж.Clone() } -func (v UserView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v UserView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v UserView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *UserView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -59,7 +70,20 @@ func (v *UserView) UnmarshalJSON(b []byte) error { return nil } var x User - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *UserView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x User + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -107,8 +131,17 @@ func (v NodeView) AsStruct() *Node { return v.ж.Clone() } -func (v NodeView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v NodeView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v NodeView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *NodeView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -117,7 +150,20 @@ func (v *NodeView) UnmarshalJSON(b []byte) error { return nil } var x Node - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *NodeView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Node + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -246,8 +292,17 @@ func (v HostinfoView) AsStruct() *Hostinfo { return v.ж.Clone() } -func (v HostinfoView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v HostinfoView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v HostinfoView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *HostinfoView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -256,7 +311,20 @@ func (v *HostinfoView) UnmarshalJSON(b []byte) error { return nil } var x Hostinfo - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *HostinfoView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Hostinfo + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -380,8 +448,17 @@ func (v NetInfoView) AsStruct() *NetInfo { return v.ж.Clone() } -func (v NetInfoView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v NetInfoView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v NetInfoView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *NetInfoView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -390,7 +467,20 @@ func (v *NetInfoView) UnmarshalJSON(b []byte) error { return nil } var x NetInfo - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *NetInfoView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x NetInfo + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -460,8 +550,17 @@ func (v LoginView) AsStruct() *Login { return v.ж.Clone() } -func (v LoginView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v LoginView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v LoginView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *LoginView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -470,7 +569,20 @@ func (v *LoginView) UnmarshalJSON(b []byte) error { return nil } var x Login - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *LoginView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Login + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -521,8 +633,17 @@ func (v DNSConfigView) AsStruct() *DNSConfig { return v.ж.Clone() } -func (v DNSConfigView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v DNSConfigView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v DNSConfigView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *DNSConfigView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -531,7 +652,20 @@ func (v *DNSConfigView) UnmarshalJSON(b []byte) error { return nil } var x DNSConfig - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *DNSConfigView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x DNSConfig + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -602,8 +736,17 @@ func (v RegisterResponseView) AsStruct() *RegisterResponse { return v.ж.Clone() } -func (v RegisterResponseView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v RegisterResponseView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v RegisterResponseView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *RegisterResponseView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -612,7 +755,20 @@ func (v *RegisterResponseView) UnmarshalJSON(b []byte) error { return nil } var x RegisterResponse - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *RegisterResponseView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x RegisterResponse + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -668,8 +824,17 @@ func (v RegisterResponseAuthView) AsStruct() *RegisterResponseAuth { return v.ж.Clone() } -func (v RegisterResponseAuthView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v RegisterResponseAuthView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v RegisterResponseAuthView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *RegisterResponseAuthView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -678,7 +843,20 @@ func (v *RegisterResponseAuthView) UnmarshalJSON(b []byte) error { return nil } var x RegisterResponseAuth - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *RegisterResponseAuthView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x RegisterResponseAuth + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -726,8 +904,17 @@ func (v RegisterRequestView) AsStruct() *RegisterRequest { return v.ж.Clone() } -func (v RegisterRequestView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v RegisterRequestView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v RegisterRequestView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *RegisterRequestView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -736,7 +923,20 @@ func (v *RegisterRequestView) UnmarshalJSON(b []byte) error { return nil } var x RegisterRequest - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *RegisterRequestView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x RegisterRequest + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -816,8 +1016,17 @@ func (v DERPHomeParamsView) AsStruct() *DERPHomeParams { return v.ж.Clone() } -func (v DERPHomeParamsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v DERPHomeParamsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v DERPHomeParamsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *DERPHomeParamsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -826,7 +1035,20 @@ func (v *DERPHomeParamsView) UnmarshalJSON(b []byte) error { return nil } var x DERPHomeParams - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *DERPHomeParamsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x DERPHomeParams + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -870,8 +1092,17 @@ func (v DERPRegionView) AsStruct() *DERPRegion { return v.ж.Clone() } -func (v DERPRegionView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v DERPRegionView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v DERPRegionView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *DERPRegionView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -880,7 +1111,20 @@ func (v *DERPRegionView) UnmarshalJSON(b []byte) error { return nil } var x DERPRegion - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *DERPRegionView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x DERPRegion + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -938,8 +1182,17 @@ func (v DERPMapView) AsStruct() *DERPMap { return v.ж.Clone() } -func (v DERPMapView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v DERPMapView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v DERPMapView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *DERPMapView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -948,7 +1201,20 @@ func (v *DERPMapView) UnmarshalJSON(b []byte) error { return nil } var x DERPMap - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *DERPMapView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x DERPMap + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -999,8 +1265,17 @@ func (v DERPNodeView) AsStruct() *DERPNode { return v.ж.Clone() } -func (v DERPNodeView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v DERPNodeView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v DERPNodeView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *DERPNodeView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -1009,7 +1284,20 @@ func (v *DERPNodeView) UnmarshalJSON(b []byte) error { return nil } var x DERPNode - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *DERPNodeView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x DERPNode + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -1073,8 +1361,17 @@ func (v SSHRuleView) AsStruct() *SSHRule { return v.ж.Clone() } -func (v SSHRuleView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v SSHRuleView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v SSHRuleView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *SSHRuleView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -1083,7 +1380,20 @@ func (v *SSHRuleView) UnmarshalJSON(b []byte) error { return nil } var x SSHRule - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *SSHRuleView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x SSHRule + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -1139,8 +1449,17 @@ func (v SSHActionView) AsStruct() *SSHAction { return v.ж.Clone() } -func (v SSHActionView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v SSHActionView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v SSHActionView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *SSHActionView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -1149,7 +1468,20 @@ func (v *SSHActionView) UnmarshalJSON(b []byte) error { return nil } var x SSHAction - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *SSHActionView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x SSHAction + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -1211,8 +1543,17 @@ func (v SSHPrincipalView) AsStruct() *SSHPrincipal { return v.ж.Clone() } -func (v SSHPrincipalView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v SSHPrincipalView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v SSHPrincipalView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *SSHPrincipalView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -1221,7 +1562,20 @@ func (v *SSHPrincipalView) UnmarshalJSON(b []byte) error { return nil } var x SSHPrincipal - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *SSHPrincipalView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x SSHPrincipal + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -1273,8 +1627,17 @@ func (v ControlDialPlanView) AsStruct() *ControlDialPlan { return v.ж.Clone() } -func (v ControlDialPlanView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v ControlDialPlanView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v ControlDialPlanView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *ControlDialPlanView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -1283,7 +1646,20 @@ func (v *ControlDialPlanView) UnmarshalJSON(b []byte) error { return nil } var x ControlDialPlan - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *ControlDialPlanView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x ControlDialPlan + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -1327,8 +1703,17 @@ func (v LocationView) AsStruct() *Location { return v.ж.Clone() } -func (v LocationView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v LocationView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v LocationView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *LocationView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -1337,7 +1722,20 @@ func (v *LocationView) UnmarshalJSON(b []byte) error { return nil } var x Location - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *LocationView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Location + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -1391,8 +1789,17 @@ func (v UserProfileView) AsStruct() *UserProfile { return v.ж.Clone() } -func (v UserProfileView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v UserProfileView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v UserProfileView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *UserProfileView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -1401,7 +1808,20 @@ func (v *UserProfileView) UnmarshalJSON(b []byte) error { return nil } var x UserProfile - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *UserProfileView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x UserProfile + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -1450,8 +1870,17 @@ func (v VIPServiceView) AsStruct() *VIPService { return v.ж.Clone() } -func (v VIPServiceView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v VIPServiceView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v VIPServiceView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *VIPServiceView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -1460,7 +1889,20 @@ func (v *VIPServiceView) UnmarshalJSON(b []byte) error { return nil } var x VIPService - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *VIPServiceView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x VIPService + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x diff --git a/types/dnstype/dnstype_view.go b/types/dnstype/dnstype_view.go index c77ff9a40..3d374ab47 100644 --- a/types/dnstype/dnstype_view.go +++ b/types/dnstype/dnstype_view.go @@ -6,10 +6,12 @@ package dnstype import ( - "encoding/json" + jsonv1 "encoding/json" "errors" "net/netip" + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "tailscale.com/types/views" ) @@ -43,8 +45,17 @@ func (v ResolverView) AsStruct() *Resolver { return v.ж.Clone() } -func (v ResolverView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v ResolverView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v ResolverView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *ResolverView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -53,7 +64,20 @@ func (v *ResolverView) UnmarshalJSON(b []byte) error { return nil } var x Resolver - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *ResolverView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Resolver + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x diff --git a/types/persist/persist_view.go b/types/persist/persist_view.go index 55eb40c51..99a86a6a5 100644 --- a/types/persist/persist_view.go +++ b/types/persist/persist_view.go @@ -6,9 +6,11 @@ package persist import ( - "encoding/json" + jsonv1 "encoding/json" "errors" + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "tailscale.com/tailcfg" "tailscale.com/types/key" "tailscale.com/types/structs" @@ -45,8 +47,17 @@ func (v PersistView) AsStruct() *Persist { return v.ж.Clone() } -func (v PersistView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v PersistView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v PersistView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *PersistView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -55,7 +66,20 @@ func (v *PersistView) UnmarshalJSON(b []byte) error { return nil } var x Persist - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *PersistView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Persist + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x diff --git a/types/prefs/prefs_example/prefs_example_view.go b/types/prefs/prefs_example/prefs_example_view.go index 9aaac6e9c..afc9f1781 100644 --- a/types/prefs/prefs_example/prefs_example_view.go +++ b/types/prefs/prefs_example/prefs_example_view.go @@ -6,10 +6,12 @@ package prefs_example import ( - "encoding/json" + jsonv1 "encoding/json" "errors" "net/netip" + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "tailscale.com/drive" "tailscale.com/tailcfg" "tailscale.com/types/opt" @@ -48,8 +50,17 @@ func (v PrefsView) AsStruct() *Prefs { return v.ж.Clone() } -func (v PrefsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v PrefsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v PrefsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *PrefsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -58,7 +69,20 @@ func (v *PrefsView) UnmarshalJSON(b []byte) error { return nil } var x Prefs - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *PrefsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x Prefs + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -160,8 +184,17 @@ func (v AutoUpdatePrefsView) AsStruct() *AutoUpdatePrefs { return v.ж.Clone() } -func (v AutoUpdatePrefsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v AutoUpdatePrefsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v AutoUpdatePrefsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *AutoUpdatePrefsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -170,7 +203,20 @@ func (v *AutoUpdatePrefsView) UnmarshalJSON(b []byte) error { return nil } var x AutoUpdatePrefs - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *AutoUpdatePrefsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x AutoUpdatePrefs + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -214,8 +260,17 @@ func (v AppConnectorPrefsView) AsStruct() *AppConnectorPrefs { return v.ж.Clone() } -func (v AppConnectorPrefsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v AppConnectorPrefsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v AppConnectorPrefsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *AppConnectorPrefsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -224,7 +279,20 @@ func (v *AppConnectorPrefsView) UnmarshalJSON(b []byte) error { return nil } var x AppConnectorPrefs - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *AppConnectorPrefsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x AppConnectorPrefs + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x diff --git a/types/prefs/prefs_view_test.go b/types/prefs/prefs_view_test.go index f6cfc918d..44c3beb87 100644 --- a/types/prefs/prefs_view_test.go +++ b/types/prefs/prefs_view_test.go @@ -6,9 +6,12 @@ package prefs import ( - "encoding/json" + jsonv1 "encoding/json" "errors" "net/netip" + + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" ) //go:generate go run tailscale.com/cmd/cloner -clonefunc=false -type=TestPrefs,TestBundle,TestValueStruct,TestGenericStruct,TestPrefsGroup -tags=test @@ -41,8 +44,17 @@ func (v TestPrefsView) AsStruct() *TestPrefs { return v.ж.Clone() } -func (v TestPrefsView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v TestPrefsView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v TestPrefsView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *TestPrefsView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -51,7 +63,20 @@ func (v *TestPrefsView) UnmarshalJSON(b []byte) error { return nil } var x TestPrefs - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *TestPrefsView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x TestPrefs + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -145,8 +170,17 @@ func (v TestBundleView) AsStruct() *TestBundle { return v.ж.Clone() } -func (v TestBundleView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v TestBundleView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v TestBundleView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *TestBundleView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -155,7 +189,20 @@ func (v *TestBundleView) UnmarshalJSON(b []byte) error { return nil } var x TestBundle - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *TestBundleView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x TestBundle + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -200,8 +247,17 @@ func (v TestValueStructView) AsStruct() *TestValueStruct { return v.ж.Clone() } -func (v TestValueStructView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v TestValueStructView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v TestValueStructView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *TestValueStructView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -210,7 +266,20 @@ func (v *TestValueStructView) UnmarshalJSON(b []byte) error { return nil } var x TestValueStruct - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *TestValueStructView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x TestValueStruct + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -253,8 +322,17 @@ func (v TestGenericStructView[T]) AsStruct() *TestGenericStruct[T] { return v.ж.Clone() } -func (v TestGenericStructView[T]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v TestGenericStructView[T]) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v TestGenericStructView[T]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *TestGenericStructView[T]) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -263,7 +341,20 @@ func (v *TestGenericStructView[T]) UnmarshalJSON(b []byte) error { return nil } var x TestGenericStruct[T] - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *TestGenericStructView[T]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x TestGenericStruct[T] + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x @@ -308,8 +399,17 @@ func (v TestPrefsGroupView) AsStruct() *TestPrefsGroup { return v.ж.Clone() } -func (v TestPrefsGroupView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v TestPrefsGroupView) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v TestPrefsGroupView) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} +// UnmarshalJSON implements [jsonv1.Unmarshaler]. func (v *TestPrefsGroupView) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") @@ -318,7 +418,20 @@ func (v *TestPrefsGroupView) UnmarshalJSON(b []byte) error { return nil } var x TestPrefsGroup - if err := json.Unmarshal(b, &x); err != nil { + if err := jsonv1.Unmarshal(b, &x); err != nil { + return err + } + v.ж = &x + return nil +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +func (v *TestPrefsGroupView) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + var x TestPrefsGroup + if err := jsonv2.UnmarshalDecode(dec, &x); err != nil { return err } v.ж = &x diff --git a/types/views/views.go b/types/views/views.go index 3911f1112..6d15b80d4 100644 --- a/types/views/views.go +++ b/types/views/views.go @@ -7,7 +7,7 @@ package views import ( "bytes" - "encoding/json" + jsonv1 "encoding/json" "errors" "fmt" "iter" @@ -15,20 +15,12 @@ import ( "reflect" "slices" + jsonv2 "github.com/go-json-experiment/json" + "github.com/go-json-experiment/json/jsontext" "go4.org/mem" "tailscale.com/types/ptr" ) -func unmarshalSliceFromJSON[T any](b []byte, x *[]T) error { - if *x != nil { - return errors.New("already initialized") - } - if len(b) == 0 { - return nil - } - return json.Unmarshal(b, x) -} - // ByteSlice is a read-only accessor for types that are backed by a []byte. type ByteSlice[T ~[]byte] struct { // ж is the underlying mutable value, named with a hard-to-type @@ -93,15 +85,32 @@ func (v ByteSlice[T]) SliceTo(i int) ByteSlice[T] { return ByteSlice[T]{v.ж[:i] // Slice returns v[i:j] func (v ByteSlice[T]) Slice(i, j int) ByteSlice[T] { return ByteSlice[T]{v.ж[i:j]} } -// MarshalJSON implements json.Marshaler. -func (v ByteSlice[T]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v ByteSlice[T]) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} -// UnmarshalJSON implements json.Unmarshaler. +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v ByteSlice[T]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. +// It must only be called on an uninitialized ByteSlice. func (v *ByteSlice[T]) UnmarshalJSON(b []byte) error { if v.ж != nil { return errors.New("already initialized") } - return json.Unmarshal(b, &v.ж) + return jsonv1.Unmarshal(b, &v.ж) +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +// It must only be called on an uninitialized ByteSlice. +func (v *ByteSlice[T]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + return jsonv2.UnmarshalDecode(dec, &v.ж) } // StructView represents the corresponding StructView of a Viewable. The concrete types are @@ -159,11 +168,35 @@ func (v SliceView[T, V]) All() iter.Seq2[int, V] { } } -// MarshalJSON implements json.Marshaler. -func (v SliceView[T, V]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } +// MarshalJSON implements [jsonv1.Marshaler]. +func (v SliceView[T, V]) MarshalJSON() ([]byte, error) { + return jsonv1.Marshal(v.ж) +} + +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v SliceView[T, V]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} -// UnmarshalJSON implements json.Unmarshaler. -func (v *SliceView[T, V]) UnmarshalJSON(b []byte) error { return unmarshalSliceFromJSON(b, &v.ж) } +// UnmarshalJSON implements [jsonv1.Unmarshaler]. +// It must only be called on an uninitialized SliceView. +func (v *SliceView[T, V]) UnmarshalJSON(b []byte) error { + if v.ж != nil { + return errors.New("already initialized") + } else if len(b) == 0 { + return nil + } + return jsonv1.Unmarshal(b, &v.ж) +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +// It must only be called on an uninitialized SliceView. +func (v *SliceView[T, V]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + return jsonv2.UnmarshalDecode(dec, &v.ж) +} // IsNil reports whether the underlying slice is nil. func (v SliceView[T, V]) IsNil() bool { return v.ж == nil } @@ -252,14 +285,34 @@ func SliceOf[T any](x []T) Slice[T] { return Slice[T]{x} } -// MarshalJSON implements json.Marshaler. +// MarshalJSON implements [jsonv1.Marshaler]. func (v Slice[T]) MarshalJSON() ([]byte, error) { - return json.Marshal(v.ж) + return jsonv1.Marshal(v.ж) } -// UnmarshalJSON implements json.Unmarshaler. +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (v Slice[T]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, v.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. +// It must only be called on an uninitialized Slice. func (v *Slice[T]) UnmarshalJSON(b []byte) error { - return unmarshalSliceFromJSON(b, &v.ж) + if v.ж != nil { + return errors.New("already initialized") + } else if len(b) == 0 { + return nil + } + return jsonv1.Unmarshal(b, &v.ж) +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +// It must only be called on an uninitialized Slice. +func (v *Slice[T]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if v.ж != nil { + return errors.New("already initialized") + } + return jsonv2.UnmarshalDecode(dec, &v.ж) } // IsNil reports whether the underlying slice is nil. @@ -512,18 +565,32 @@ func (m MapSlice[K, V]) GetOk(k K) (Slice[V], bool) { return SliceOf(v), ok } -// MarshalJSON implements json.Marshaler. +// MarshalJSON implements [jsonv1.Marshaler]. func (m MapSlice[K, V]) MarshalJSON() ([]byte, error) { - return json.Marshal(m.ж) + return jsonv1.Marshal(m.ж) } -// UnmarshalJSON implements json.Unmarshaler. +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (m MapSlice[K, V]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, m.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. // It should only be called on an uninitialized Map. func (m *MapSlice[K, V]) UnmarshalJSON(b []byte) error { if m.ж != nil { return errors.New("already initialized") } - return json.Unmarshal(b, &m.ж) + return jsonv1.Unmarshal(b, &m.ж) +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +// It should only be called on an uninitialized MapSlice. +func (m *MapSlice[K, V]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if m.ж != nil { + return errors.New("already initialized") + } + return jsonv2.UnmarshalDecode(dec, &m.ж) } // AsMap returns a shallow-clone of the underlying map. @@ -600,18 +667,32 @@ func (m Map[K, V]) GetOk(k K) (V, bool) { return v, ok } -// MarshalJSON implements json.Marshaler. +// MarshalJSON implements [jsonv1.Marshaler]. func (m Map[K, V]) MarshalJSON() ([]byte, error) { - return json.Marshal(m.ж) + return jsonv1.Marshal(m.ж) } -// UnmarshalJSON implements json.Unmarshaler. +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (m Map[K, V]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, m.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. // It should only be called on an uninitialized Map. func (m *Map[K, V]) UnmarshalJSON(b []byte) error { if m.ж != nil { return errors.New("already initialized") } - return json.Unmarshal(b, &m.ж) + return jsonv1.Unmarshal(b, &m.ж) +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +// It must only be called on an uninitialized Map. +func (m *Map[K, V]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if m.ж != nil { + return errors.New("already initialized") + } + return jsonv2.UnmarshalDecode(dec, &m.ж) } // AsMap returns a shallow-clone of the underlying map. @@ -809,17 +890,32 @@ func ValuePointerOf[T any](v *T) ValuePointer[T] { return ValuePointer[T]{v} } -// MarshalJSON implements [json.Marshaler]. +// MarshalJSON implements [jsonv1.Marshaler]. func (p ValuePointer[T]) MarshalJSON() ([]byte, error) { - return json.Marshal(p.ж) + return jsonv1.Marshal(p.ж) } -// UnmarshalJSON implements [json.Unmarshaler]. +// MarshalJSONTo implements [jsonv2.MarshalerTo]. +func (p ValuePointer[T]) MarshalJSONTo(enc *jsontext.Encoder) error { + return jsonv2.MarshalEncode(enc, p.ж) +} + +// UnmarshalJSON implements [jsonv1.Unmarshaler]. +// It must only be called on an uninitialized ValuePointer. func (p *ValuePointer[T]) UnmarshalJSON(b []byte) error { if p.ж != nil { return errors.New("already initialized") } - return json.Unmarshal(b, &p.ж) + return jsonv1.Unmarshal(b, &p.ж) +} + +// UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom]. +// It must only be called on an uninitialized ValuePointer. +func (p *ValuePointer[T]) UnmarshalJSONFrom(dec *jsontext.Decoder) error { + if p.ж != nil { + return errors.New("already initialized") + } + return jsonv2.UnmarshalDecode(dec, &p.ж) } // ContainsPointers reports whether T contains any pointers, diff --git a/types/views/views_test.go b/types/views/views_test.go index 2205cbc03..5a30c11a1 100644 --- a/types/views/views_test.go +++ b/types/views/views_test.go @@ -4,8 +4,7 @@ package views import ( - "bytes" - "encoding/json" + jsonv1 "encoding/json" "fmt" "net/netip" "reflect" @@ -15,9 +14,27 @@ import ( "unsafe" qt "github.com/frankban/quicktest" + jsonv2 "github.com/go-json-experiment/json" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "tailscale.com/types/structs" ) +// Statically verify that each type implements the following interfaces. +var _ = []interface { + jsonv1.Marshaler + jsonv1.Unmarshaler + jsonv2.MarshalerTo + jsonv2.UnmarshalerFrom +}{ + (*ByteSlice[[]byte])(nil), + (*SliceView[*testStruct, testStructView])(nil), + (*Slice[testStruct])(nil), + (*MapSlice[*testStruct, testStructView])(nil), + (*Map[*testStruct, testStructView])(nil), + (*ValuePointer[testStruct])(nil), +} + type viewStruct struct { Int int Addrs Slice[netip.Prefix] @@ -83,14 +100,16 @@ func TestViewsJSON(t *testing.T) { ipp := SliceOf(mustCIDR("192.168.0.0/24")) ss := SliceOf([]string{"bar"}) tests := []struct { - name string - in viewStruct - wantJSON string + name string + in viewStruct + wantJSONv1 string + wantJSONv2 string }{ { - name: "empty", - in: viewStruct{}, - wantJSON: `{"Int":0,"Addrs":null,"Strings":null}`, + name: "empty", + in: viewStruct{}, + wantJSONv1: `{"Int":0,"Addrs":null,"Strings":null}`, + wantJSONv2: `{"Int":0,"Addrs":[],"Strings":[]}`, }, { name: "everything", @@ -101,30 +120,49 @@ func TestViewsJSON(t *testing.T) { StringsPtr: &ss, Strings: ss, }, - wantJSON: `{"Int":1234,"Addrs":["192.168.0.0/24"],"Strings":["bar"],"AddrsPtr":["192.168.0.0/24"],"StringsPtr":["bar"]}`, + wantJSONv1: `{"Int":1234,"Addrs":["192.168.0.0/24"],"Strings":["bar"],"AddrsPtr":["192.168.0.0/24"],"StringsPtr":["bar"]}`, + wantJSONv2: `{"Int":1234,"Addrs":["192.168.0.0/24"],"Strings":["bar"],"AddrsPtr":["192.168.0.0/24"],"StringsPtr":["bar"]}`, }, } - var buf bytes.Buffer - encoder := json.NewEncoder(&buf) - encoder.SetIndent("", "") for _, tc := range tests { - buf.Reset() - if err := encoder.Encode(&tc.in); err != nil { - t.Fatal(err) - } - b := buf.Bytes() - gotJSON := strings.TrimSpace(string(b)) - if tc.wantJSON != gotJSON { - t.Fatalf("JSON: %v; want: %v", gotJSON, tc.wantJSON) - } - var got viewStruct - if err := json.Unmarshal(b, &got); err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(got, tc.in) { - t.Fatalf("unmarshal resulted in different output: %+v; want %+v", got, tc.in) + cmpOpts := cmp.Options{ + cmp.AllowUnexported(Slice[string]{}), + cmp.AllowUnexported(Slice[netip.Prefix]{}), + cmpopts.EquateComparable(netip.Prefix{}), } + t.Run("JSONv1", func(t *testing.T) { + gotJSON, err := jsonv1.Marshal(tc.in) + if err != nil { + t.Fatal(err) + } + if string(gotJSON) != tc.wantJSONv1 { + t.Fatalf("JSON: %s; want: %s", gotJSON, tc.wantJSONv1) + } + var got viewStruct + if err := jsonv1.Unmarshal(gotJSON, &got); err != nil { + t.Fatal(err) + } + if d := cmp.Diff(got, tc.in, cmpOpts); d != "" { + t.Fatalf("unmarshal mismatch (-got +want):\n%s", d) + } + }) + t.Run("JSONv2", func(t *testing.T) { + gotJSON, err := jsonv2.Marshal(tc.in) + if err != nil { + t.Fatal(err) + } + if string(gotJSON) != tc.wantJSONv2 { + t.Fatalf("JSON: %s; want: %s", gotJSON, tc.wantJSONv2) + } + var got viewStruct + if err := jsonv2.Unmarshal(gotJSON, &got); err != nil { + t.Fatal(err) + } + if d := cmp.Diff(got, tc.in, cmpOpts, cmpopts.EquateEmpty()); d != "" { + t.Fatalf("unmarshal mismatch (-got +want):\n%s", d) + } + }) } } diff --git a/util/codegen/codegen.go b/util/codegen/codegen.go index 1b3af10e0..ec02d652b 100644 --- a/util/codegen/codegen.go +++ b/util/codegen/codegen.go @@ -85,28 +85,35 @@ func NewImportTracker(thisPkg *types.Package) *ImportTracker { } } +type namePkgPath struct { + name string // optional import name + pkgPath string +} + // ImportTracker provides a mechanism to track and build import paths. type ImportTracker struct { thisPkg *types.Package - packages map[string]bool + packages map[namePkgPath]bool } -func (it *ImportTracker) Import(pkg string) { - if pkg != "" && !it.packages[pkg] { - mak.Set(&it.packages, pkg, true) +// Import imports pkgPath under an optional import name. +func (it *ImportTracker) Import(name, pkgPath string) { + if pkgPath != "" && !it.packages[namePkgPath{name, pkgPath}] { + mak.Set(&it.packages, namePkgPath{name, pkgPath}, true) } } -// Has reports whether the specified package has been imported. -func (it *ImportTracker) Has(pkg string) bool { - return it.packages[pkg] +// Has reports whether the specified package path has been imported +// under the particular import name. +func (it *ImportTracker) Has(name, pkgPath string) bool { + return it.packages[namePkgPath{name, pkgPath}] } func (it *ImportTracker) qualifier(pkg *types.Package) string { if it.thisPkg == pkg { return "" } - it.Import(pkg.Path()) + it.Import("", pkg.Path()) // TODO(maisem): handle conflicts? return pkg.Name() } @@ -128,7 +135,11 @@ func (it *ImportTracker) PackagePrefix(pkg *types.Package) string { func (it *ImportTracker) Write(w io.Writer) { fmt.Fprintf(w, "import (\n") for s := range it.packages { - fmt.Fprintf(w, "\t%q\n", s) + if s.name == "" { + fmt.Fprintf(w, "\t%q\n", s.pkgPath) + } else { + fmt.Fprintf(w, "\t%s %q\n", s.name, s.pkgPath) + } } fmt.Fprintf(w, ")\n\n") }