Skip to content

Commit

Permalink
Use constructors for static tokens
Browse files Browse the repository at this point in the history
WARNING: This commit includes breaking changes.

Instead of global variables, use function constructors
for static tokens such as Null, ObjectStart, ObjectEnd,
ArrayStart, and ArrayEnd. This provides a greater degree
of immutability for the API.

Note that static tokens for True and False are dropped
in favor of the pre-existing Bool constructor.
If necessary, we can already re-introduce True and False.
  • Loading branch information
dsnet committed Apr 12, 2024
1 parent b15d3ef commit 5df3330
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 214 deletions.
2 changes: 1 addition & 1 deletion arshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) {
func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err error) {
v := reflect.ValueOf(in)
if !v.IsValid() || (v.Kind() == reflect.Pointer && v.IsNil()) {
return out.WriteToken(jsontext.Null)
return out.WriteToken(jsontext.Null())
}
// Shallow copy non-pointer values to obtain an addressable value.
// It is beneficial to performance to always pass pointers to avoid this.
Expand Down
14 changes: 7 additions & 7 deletions arshal_any.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
func marshalValueAny(enc *jsontext.Encoder, val any, mo *jsonopts.Struct) error {
switch val := val.(type) {
case nil:
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
case bool:
return enc.WriteToken(jsontext.Bool(val))
case string:
Expand Down Expand Up @@ -96,7 +96,7 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St
// Handle empty maps.
if len(obj) == 0 {
if mo.Flags.Get(jsonflags.FormatNilMapAsNull) && obj == nil {
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
}
// Optimize for marshaling an empty map without any preceding whitespace.
if !xe.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() {
Expand All @@ -109,7 +109,7 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St
}
}

if err := enc.WriteToken(jsontext.ObjectStart); err != nil {
if err := enc.WriteToken(jsontext.ObjectStart()); err != nil {
return err
}
// A Go map guarantees that each entry has a unique key
Expand Down Expand Up @@ -144,7 +144,7 @@ func marshalObjectAny(enc *jsontext.Encoder, obj map[string]any, mo *jsonopts.St
}
putStrings(names)
}
if err := enc.WriteToken(jsontext.ObjectEnd); err != nil {
if err := enc.WriteToken(jsontext.ObjectEnd()); err != nil {
return err
}
return nil
Expand Down Expand Up @@ -209,7 +209,7 @@ func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) erro
// Handle empty slices.
if len(arr) == 0 {
if mo.Flags.Get(jsonflags.FormatNilSliceAsNull) && arr == nil {
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
}
// Optimize for marshaling an empty slice without any preceding whitespace.
if !xe.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() {
Expand All @@ -222,15 +222,15 @@ func marshalArrayAny(enc *jsontext.Encoder, arr []any, mo *jsonopts.Struct) erro
}
}

if err := enc.WriteToken(jsontext.ArrayStart); err != nil {
if err := enc.WriteToken(jsontext.ArrayStart()); err != nil {
return err
}
for _, val := range arr {
if err := marshalValueAny(enc, val, mo); err != nil {
return err
}
}
if err := enc.WriteToken(jsontext.ArrayEnd); err != nil {
if err := enc.WriteToken(jsontext.ArrayEnd()); err != nil {
return err
}
return nil
Expand Down
26 changes: 13 additions & 13 deletions arshal_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func makeBytesArshaler(t reflect.Type, fncs *arshaler) *arshaler {
}
if mo.Flags.Get(jsonflags.FormatNilSliceAsNull) && va.Kind() == reflect.Slice && va.IsNil() {
// TODO: Provide a "emitempty" format override?
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
}
val := enc.UnusedBuffer()
b := va.Bytes()
Expand Down Expand Up @@ -648,7 +648,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
n := va.Len()
if n == 0 {
if emitNull && va.IsNil() {
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
}
// Optimize for marshaling an empty map without any preceding whitespace.
if optimizeCommon && !xe.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() {
Expand All @@ -662,7 +662,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
}

once.Do(init)
if err := enc.WriteToken(jsontext.ObjectStart); err != nil {
if err := enc.WriteToken(jsontext.ObjectStart()); err != nil {
return err
}
if n > 0 {
Expand Down Expand Up @@ -767,7 +767,7 @@ func makeMapArshaler(t reflect.Type) *arshaler {
}
}
}
if err := enc.WriteToken(jsontext.ObjectEnd); err != nil {
if err := enc.WriteToken(jsontext.ObjectEnd()); err != nil {
return err
}
return nil
Expand Down Expand Up @@ -918,7 +918,7 @@ func makeStructArshaler(t reflect.Type) *arshaler {
err.action = "marshal"
return &err
}
if err := enc.WriteToken(jsontext.ObjectStart); err != nil {
if err := enc.WriteToken(jsontext.ObjectStart()); err != nil {
return err
}
var seenIdxs uintSet
Expand Down Expand Up @@ -1064,7 +1064,7 @@ func makeStructArshaler(t reflect.Type) *arshaler {
return err
}
}
if err := enc.WriteToken(jsontext.ObjectEnd); err != nil {
if err := enc.WriteToken(jsontext.ObjectEnd()); err != nil {
return err
}
return nil
Expand Down Expand Up @@ -1253,7 +1253,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler {
n := va.Len()
if n == 0 {
if emitNull && va.IsNil() {
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
}
// Optimize for marshaling an empty slice without any preceding whitespace.
if optimizeCommon && !xe.Flags.Get(jsonflags.AnyWhitespace) && !xe.Tokens.Last.NeedObjectName() {
Expand All @@ -1267,7 +1267,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler {
}

once.Do(init)
if err := enc.WriteToken(jsontext.ArrayStart); err != nil {
if err := enc.WriteToken(jsontext.ArrayStart()); err != nil {
return err
}
marshal := valFncs.marshal
Expand All @@ -1280,7 +1280,7 @@ func makeSliceArshaler(t reflect.Type) *arshaler {
return err
}
}
if err := enc.WriteToken(jsontext.ArrayEnd); err != nil {
if err := enc.WriteToken(jsontext.ArrayEnd()); err != nil {
return err
}
return nil
Expand Down Expand Up @@ -1366,7 +1366,7 @@ func makeArrayArshaler(t reflect.Type) *arshaler {
return newInvalidFormatError("marshal", t, mo.Format)
}
once.Do(init)
if err := enc.WriteToken(jsontext.ArrayStart); err != nil {
if err := enc.WriteToken(jsontext.ArrayStart()); err != nil {
return err
}
marshal := valFncs.marshal
Expand All @@ -1379,7 +1379,7 @@ func makeArrayArshaler(t reflect.Type) *arshaler {
return err
}
}
if err := enc.WriteToken(jsontext.ArrayEnd); err != nil {
if err := enc.WriteToken(jsontext.ArrayEnd()); err != nil {
return err
}
return nil
Expand Down Expand Up @@ -1464,7 +1464,7 @@ func makePointerArshaler(t reflect.Type) *arshaler {

// NOTE: Struct.Format is forwarded to underlying marshal.
if va.IsNil() {
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
}
once.Do(init)
marshal := valFncs.marshal
Expand Down Expand Up @@ -1509,7 +1509,7 @@ func makeInterfaceArshaler(t reflect.Type) *arshaler {
return newInvalidFormatError("marshal", t, mo.Format)
}
if va.IsNil() {
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
}
v := newAddressableValue(va.Elem().Type())
v.Set(va.Elem())
Expand Down
10 changes: 5 additions & 5 deletions arshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3118,8 +3118,8 @@ func TestMarshal(t *testing.T) {
}, {
name: jsontest.Name("Methods/Invalid/JSONv2/TooMany"),
in: marshalJSONv2Func(func(enc *jsontext.Encoder, opts Options) error {
enc.WriteToken(jsontext.Null)
enc.WriteToken(jsontext.Null)
enc.WriteToken(jsontext.Null())
enc.WriteToken(jsontext.Null())
return nil
}),
want: `nullnull`,
Expand Down Expand Up @@ -3198,7 +3198,7 @@ func TestMarshal(t *testing.T) {
name: jsontest.Name("Methods/Invalid/MapKey/JSONv2/Syntax"),
in: map[any]string{
addr(marshalJSONv2Func(func(enc *jsontext.Encoder, opts Options) error {
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
})): "invalid",
},
want: `{`,
Expand Down Expand Up @@ -3483,7 +3483,7 @@ func TestMarshal(t *testing.T) {
name: jsontest.Name("Functions/Map/Key/NoCaseString/V2/InvalidToken"),
opts: []Options{
WithMarshalers(MarshalFuncV2(func(enc *jsontext.Encoder, v nocaseString, opts Options) error {
return enc.WriteToken(jsontext.Null)
return enc.WriteToken(jsontext.Null())
})),
},
in: map[nocaseString]string{"hello": "world"},
Expand Down Expand Up @@ -8469,7 +8469,7 @@ func TestMarshalInvalidNamespace(t *testing.T) {
t.Fatalf("%s: MarshalEncode error is nil, want non-nil", tt.name.Where)
}
for _, tok := range []jsontext.Token{
jsontext.Null, jsontext.String(""), jsontext.Int(0), jsontext.ObjectStart, jsontext.ObjectEnd, jsontext.ArrayStart, jsontext.ArrayEnd,
jsontext.Null(), jsontext.String(""), jsontext.Int(0), jsontext.ObjectStart(), jsontext.ObjectEnd(), jsontext.ArrayStart(), jsontext.ArrayEnd(),
} {
if err := enc.WriteToken(tok); err == nil {
t.Fatalf("%s: WriteToken error is nil, want non-nil", tt.name.Where)
Expand Down
4 changes: 2 additions & 2 deletions example_orderedobject_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type ObjectMember[V any] struct {

// MarshalJSONV2 encodes obj as a JSON object into enc.
func (obj *OrderedObject[V]) MarshalJSONV2(enc *jsontext.Encoder, opts json.Options) error {
if err := enc.WriteToken(jsontext.ObjectStart); err != nil {
if err := enc.WriteToken(jsontext.ObjectStart()); err != nil {
return err
}
for i := range *obj {
Expand All @@ -42,7 +42,7 @@ func (obj *OrderedObject[V]) MarshalJSONV2(enc *jsontext.Encoder, opts json.Opti
return err
}
}
if err := enc.WriteToken(jsontext.ObjectEnd); err != nil {
if err := enc.WriteToken(jsontext.ObjectEnd()); err != nil {
return err
}
return nil
Expand Down
Loading

0 comments on commit 5df3330

Please sign in to comment.