From a256f166e92572cb149818fc104fef7afb82e7e7 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Fri, 12 Apr 2024 13:28:02 -0700 Subject: [PATCH] Use new reflect.TypeFor function available in Go 1.22 (#28) --- .github/workflows/test.yml | 4 +- arshal_default.go | 18 +++---- arshal_funcs.go | 8 +-- arshal_inlined.go | 2 +- arshal_methods.go | 16 +++--- arshal_test.go | 106 ++++++++++++++++++------------------- arshal_time.go | 4 +- errors_test.go | 18 +++---- fields.go | 2 +- fields_test.go | 2 +- fold_test.go | 2 +- 11 files changed, 91 insertions(+), 91 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a415a02..646d4d2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ jobs: - name: Install Go uses: actions/setup-go@v5 with: - go-version: 1.21.x + go-version: 1.22.x - name: Checkout code uses: actions/checkout@v4 - name: Test @@ -23,7 +23,7 @@ jobs: test-all: strategy: matrix: - go-version: [1.21.x] + go-version: [1.22.x] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: diff --git a/arshal_default.go b/arshal_default.go index 30abd36..45ea858 100644 --- a/arshal_default.go +++ b/arshal_default.go @@ -30,15 +30,15 @@ const optimizeCommon = true var ( // Most natural Go type that correspond with each JSON type. - anyType = reflect.TypeOf((*any)(nil)).Elem() // JSON value - boolType = reflect.TypeOf((*bool)(nil)).Elem() // JSON bool - stringType = reflect.TypeOf((*string)(nil)).Elem() // JSON string - float64Type = reflect.TypeOf((*float64)(nil)).Elem() // JSON number - mapStringAnyType = reflect.TypeOf((*map[string]any)(nil)).Elem() // JSON object - sliceAnyType = reflect.TypeOf((*[]any)(nil)).Elem() // JSON array - - bytesType = reflect.TypeOf((*[]byte)(nil)).Elem() - emptyStructType = reflect.TypeOf((*struct{})(nil)).Elem() + anyType = reflect.TypeFor[any]() // JSON value + boolType = reflect.TypeFor[bool]() // JSON bool + stringType = reflect.TypeFor[string]() // JSON string + float64Type = reflect.TypeFor[float64]() // JSON number + mapStringAnyType = reflect.TypeFor[map[string]any]() // JSON object + sliceAnyType = reflect.TypeFor[[]any]() // JSON array + + bytesType = reflect.TypeFor[[]byte]() + emptyStructType = reflect.TypeFor[struct{}]() ) const startDetectingCyclesAfter = 1000 diff --git a/arshal_funcs.go b/arshal_funcs.go index e608d75..1774957 100644 --- a/arshal_funcs.go +++ b/arshal_funcs.go @@ -166,7 +166,7 @@ func (a *typedArshalers[Coder]) lookup(fnc func(*Coder, addressableValue, *jsono // The value of T must not be retained outside the function call. // It may not return [SkipFunc]. func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers { - t := reflect.TypeOf((*T)(nil)).Elem() + t := reflect.TypeFor[T]() assertCastableTo(t, true) typFnc := typedMarshaler{ typ: t, @@ -200,7 +200,7 @@ func MarshalFuncV1[T any](fn func(T) ([]byte, error)) *Marshalers { // The pointer to [jsontext.Encoder], the value of T, and the [Options] value // must not be retained outside the function call. func MarshalFuncV2[T any](fn func(*jsontext.Encoder, T, Options) error) *Marshalers { - t := reflect.TypeOf((*T)(nil)).Elem() + t := reflect.TypeFor[T]() assertCastableTo(t, true) typFnc := typedMarshaler{ typ: t, @@ -241,7 +241,7 @@ func MarshalFuncV2[T any](fn func(*jsontext.Encoder, T, Options) error) *Marshal // The input []byte and value T must not be retained outside the function call. // It may not return [SkipFunc]. func UnmarshalFuncV1[T any](fn func([]byte, T) error) *Unmarshalers { - t := reflect.TypeOf((*T)(nil)).Elem() + t := reflect.TypeFor[T]() assertCastableTo(t, false) typFnc := typedUnmarshaler{ typ: t, @@ -274,7 +274,7 @@ func UnmarshalFuncV1[T any](fn func([]byte, T) error) *Unmarshalers { // The pointer to [jsontext.Decoder], the value of T, and [Options] value // must not be retained outside the function call. func UnmarshalFuncV2[T any](fn func(*jsontext.Decoder, T, Options) error) *Unmarshalers { - t := reflect.TypeOf((*T)(nil)).Elem() + t := reflect.TypeFor[T]() assertCastableTo(t, false) typFnc := typedUnmarshaler{ typ: t, diff --git a/arshal_inlined.go b/arshal_inlined.go index 51e05f9..f78690f 100644 --- a/arshal_inlined.go +++ b/arshal_inlined.go @@ -29,7 +29,7 @@ import ( // represent any arbitrary JSON object member. Explicitly named fields take // precedence over the inlined fallback. Only one inlined fallback is allowed. -var jsontextValueType = reflect.TypeOf((*jsontext.Value)(nil)).Elem() +var jsontextValueType = reflect.TypeFor[jsontext.Value]() // marshalInlinedFallbackAll marshals all the members in an inlined fallback. func marshalInlinedFallbackAll(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct, f *structField, insertUnquotedName func([]byte) bool) error { diff --git a/arshal_methods.go b/arshal_methods.go index f7277c9..dd96f15 100644 --- a/arshal_methods.go +++ b/arshal_methods.go @@ -17,18 +17,18 @@ import ( // Interfaces for custom serialization. var ( - jsonMarshalerV1Type = reflect.TypeOf((*MarshalerV1)(nil)).Elem() - jsonMarshalerV2Type = reflect.TypeOf((*MarshalerV2)(nil)).Elem() - jsonUnmarshalerV1Type = reflect.TypeOf((*UnmarshalerV1)(nil)).Elem() - jsonUnmarshalerV2Type = reflect.TypeOf((*UnmarshalerV2)(nil)).Elem() - textAppenderType = reflect.TypeOf((*encodingTextAppender)(nil)).Elem() - textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() - textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + jsonMarshalerV1Type = reflect.TypeFor[MarshalerV1]() + jsonMarshalerV2Type = reflect.TypeFor[MarshalerV2]() + jsonUnmarshalerV1Type = reflect.TypeFor[UnmarshalerV1]() + jsonUnmarshalerV2Type = reflect.TypeFor[UnmarshalerV2]() + textAppenderType = reflect.TypeFor[encodingTextAppender]() + textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]() + textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]() // TODO(https://go.dev/issue/62384): Use encoding.TextAppender instead of this hack. // This exists for now to provide performance benefits to netip types. // There is no semantic difference with this change. - appenderToType = reflect.TypeOf((*interface{ AppendTo([]byte) []byte })(nil)).Elem() + appenderToType = reflect.TypeFor[interface{ AppendTo([]byte) []byte }]() ) // TODO(https://go.dev/issue/62384): Use encoding.TextAppender instead diff --git a/arshal_test.go b/arshal_test.go index 5ee6481..f207b9a 100644 --- a/arshal_test.go +++ b/arshal_test.go @@ -600,54 +600,54 @@ func (valueStringer) String() string { return "" } func (*pointerStringer) String() string { return "" } var ( - namedBoolType = reflect.TypeOf((*namedBool)(nil)).Elem() - intType = reflect.TypeOf((*int)(nil)).Elem() - int8Type = reflect.TypeOf((*int8)(nil)).Elem() - int16Type = reflect.TypeOf((*int16)(nil)).Elem() - int32Type = reflect.TypeOf((*int32)(nil)).Elem() - int64Type = reflect.TypeOf((*int64)(nil)).Elem() - uintType = reflect.TypeOf((*uint)(nil)).Elem() - uint8Type = reflect.TypeOf((*uint8)(nil)).Elem() - uint16Type = reflect.TypeOf((*uint16)(nil)).Elem() - uint32Type = reflect.TypeOf((*uint32)(nil)).Elem() - uint64Type = reflect.TypeOf((*uint64)(nil)).Elem() - float32Type = reflect.TypeOf((*float32)(nil)).Elem() - sliceStringType = reflect.TypeOf((*[]string)(nil)).Elem() - array1StringType = reflect.TypeOf((*[1]string)(nil)).Elem() - array0ByteType = reflect.TypeOf((*[0]byte)(nil)).Elem() - array1ByteType = reflect.TypeOf((*[1]byte)(nil)).Elem() - array2ByteType = reflect.TypeOf((*[2]byte)(nil)).Elem() - array3ByteType = reflect.TypeOf((*[3]byte)(nil)).Elem() - array4ByteType = reflect.TypeOf((*[4]byte)(nil)).Elem() - mapStringStringType = reflect.TypeOf((*map[string]string)(nil)).Elem() - structAllType = reflect.TypeOf((*structAll)(nil)).Elem() - structConflictingType = reflect.TypeOf((*structConflicting)(nil)).Elem() - structNoneExportedType = reflect.TypeOf((*structNoneExported)(nil)).Elem() - structMalformedTagType = reflect.TypeOf((*structMalformedTag)(nil)).Elem() - structUnexportedTagType = reflect.TypeOf((*structUnexportedTag)(nil)).Elem() - structUnexportedEmbeddedType = reflect.TypeOf((*structUnexportedEmbedded)(nil)).Elem() - structUnknownTextValueType = reflect.TypeOf((*structUnknownTextValue)(nil)).Elem() - allMethodsType = reflect.TypeOf((*allMethods)(nil)).Elem() - allMethodsExceptJSONv2Type = reflect.TypeOf((*allMethodsExceptJSONv2)(nil)).Elem() - allMethodsExceptJSONv1Type = reflect.TypeOf((*allMethodsExceptJSONv1)(nil)).Elem() - allMethodsExceptTextType = reflect.TypeOf((*allMethodsExceptText)(nil)).Elem() - onlyMethodJSONv2Type = reflect.TypeOf((*onlyMethodJSONv2)(nil)).Elem() - onlyMethodJSONv1Type = reflect.TypeOf((*onlyMethodJSONv1)(nil)).Elem() - onlyMethodTextType = reflect.TypeOf((*onlyMethodText)(nil)).Elem() - structMethodJSONv2Type = reflect.TypeOf((*structMethodJSONv2)(nil)).Elem() - structMethodJSONv1Type = reflect.TypeOf((*structMethodJSONv1)(nil)).Elem() - structMethodTextType = reflect.TypeOf((*structMethodText)(nil)).Elem() - marshalJSONv2FuncType = reflect.TypeOf((*marshalJSONv2Func)(nil)).Elem() - marshalJSONv1FuncType = reflect.TypeOf((*marshalJSONv1Func)(nil)).Elem() - appendTextFuncType = reflect.TypeOf((*appendTextFunc)(nil)).Elem() - marshalTextFuncType = reflect.TypeOf((*marshalTextFunc)(nil)).Elem() - unmarshalJSONv2FuncType = reflect.TypeOf((*unmarshalJSONv2Func)(nil)).Elem() - unmarshalJSONv1FuncType = reflect.TypeOf((*unmarshalJSONv1Func)(nil)).Elem() - unmarshalTextFuncType = reflect.TypeOf((*unmarshalTextFunc)(nil)).Elem() - nocaseStringType = reflect.TypeOf((*nocaseString)(nil)).Elem() - ioReaderType = reflect.TypeOf((*io.Reader)(nil)).Elem() - fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() - chanStringType = reflect.TypeOf((*chan string)(nil)).Elem() + namedBoolType = reflect.TypeFor[namedBool]() + intType = reflect.TypeFor[int]() + int8Type = reflect.TypeFor[int8]() + int16Type = reflect.TypeFor[int16]() + int32Type = reflect.TypeFor[int32]() + int64Type = reflect.TypeFor[int64]() + uintType = reflect.TypeFor[uint]() + uint8Type = reflect.TypeFor[uint8]() + uint16Type = reflect.TypeFor[uint16]() + uint32Type = reflect.TypeFor[uint32]() + uint64Type = reflect.TypeFor[uint64]() + float32Type = reflect.TypeFor[float32]() + sliceStringType = reflect.TypeFor[[]string]() + array1StringType = reflect.TypeFor[[1]string]() + array0ByteType = reflect.TypeFor[[0]byte]() + array1ByteType = reflect.TypeFor[[1]byte]() + array2ByteType = reflect.TypeFor[[2]byte]() + array3ByteType = reflect.TypeFor[[3]byte]() + array4ByteType = reflect.TypeFor[[4]byte]() + mapStringStringType = reflect.TypeFor[map[string]string]() + structAllType = reflect.TypeFor[structAll]() + structConflictingType = reflect.TypeFor[structConflicting]() + structNoneExportedType = reflect.TypeFor[structNoneExported]() + structMalformedTagType = reflect.TypeFor[structMalformedTag]() + structUnexportedTagType = reflect.TypeFor[structUnexportedTag]() + structUnexportedEmbeddedType = reflect.TypeFor[structUnexportedEmbedded]() + structUnknownTextValueType = reflect.TypeFor[structUnknownTextValue]() + allMethodsType = reflect.TypeFor[allMethods]() + allMethodsExceptJSONv2Type = reflect.TypeFor[allMethodsExceptJSONv2]() + allMethodsExceptJSONv1Type = reflect.TypeFor[allMethodsExceptJSONv1]() + allMethodsExceptTextType = reflect.TypeFor[allMethodsExceptText]() + onlyMethodJSONv2Type = reflect.TypeFor[onlyMethodJSONv2]() + onlyMethodJSONv1Type = reflect.TypeFor[onlyMethodJSONv1]() + onlyMethodTextType = reflect.TypeFor[onlyMethodText]() + structMethodJSONv2Type = reflect.TypeFor[structMethodJSONv2]() + structMethodJSONv1Type = reflect.TypeFor[structMethodJSONv1]() + structMethodTextType = reflect.TypeFor[structMethodText]() + marshalJSONv2FuncType = reflect.TypeFor[marshalJSONv2Func]() + marshalJSONv1FuncType = reflect.TypeFor[marshalJSONv1Func]() + appendTextFuncType = reflect.TypeFor[appendTextFunc]() + marshalTextFuncType = reflect.TypeFor[marshalTextFunc]() + unmarshalJSONv2FuncType = reflect.TypeFor[unmarshalJSONv2Func]() + unmarshalJSONv1FuncType = reflect.TypeFor[unmarshalJSONv1Func]() + unmarshalTextFuncType = reflect.TypeFor[unmarshalTextFunc]() + nocaseStringType = reflect.TypeFor[nocaseString]() + ioReaderType = reflect.TypeFor[io.Reader]() + fmtStringerType = reflect.TypeFor[fmt.Stringer]() + chanStringType = reflect.TypeFor[chan string]() ) func addr[T any](v T) *T { @@ -913,7 +913,7 @@ func TestMarshal(t *testing.T) { name: jsontest.Name("Maps/DuplicateName/NoCaseString"), in: map[nocaseString]string{"hello": "", "HELLO": ""}, want: `{"hello":""`, - wantErr: &SemanticError{action: "marshal", JSONKind: '"', GoType: reflect.TypeOf(nocaseString("")), Err: export.NewDuplicateNameError([]byte(`"hello"`), len64(`{"hello":"",`))}, + wantErr: &SemanticError{action: "marshal", JSONKind: '"', GoType: reflect.TypeFor[nocaseString](), Err: export.NewDuplicateNameError([]byte(`"hello"`), len64(`{"hello":"",`))}, }, { name: jsontest.Name("Maps/DuplicateName/NaNs/Deterministic+AllowDuplicateNames"), opts: []Options{ @@ -1036,7 +1036,7 @@ func TestMarshal(t *testing.T) { return m }(), want: strings.Repeat(`{"k":`, startDetectingCyclesAfter) + `{"k"`, - wantErr: &SemanticError{action: "marshal", GoType: reflect.TypeOf(recursiveMap{}), Err: errors.New("encountered a cycle")}, + wantErr: &SemanticError{action: "marshal", GoType: reflect.TypeFor[recursiveMap](), Err: errors.New("encountered a cycle")}, }, { name: jsontest.Name("Maps/IgnoreInvalidFormat"), opts: []Options{invalidFormatOption}, @@ -1813,7 +1813,7 @@ func TestMarshal(t *testing.T) { for i := 0; i < 100; i++ { fields = append(fields, reflect.StructField{ Name: fmt.Sprintf("X%d", i), - Type: reflect.TypeOf(stringMarshalEmpty("")), + Type: reflect.TypeFor[stringMarshalEmpty](), Tag: `json:",omitempty"`, }) } @@ -2661,7 +2661,7 @@ func TestMarshal(t *testing.T) { return s }(), want: strings.Repeat(`[`, startDetectingCyclesAfter) + `[`, - wantErr: &SemanticError{action: "marshal", GoType: reflect.TypeOf(recursiveSlice{}), Err: errors.New("encountered a cycle")}, + wantErr: &SemanticError{action: "marshal", GoType: reflect.TypeFor[recursiveSlice](), Err: errors.New("encountered a cycle")}, }, { name: jsontest.Name("Slices/NonCyclicSlice"), in: func() []any { @@ -2756,7 +2756,7 @@ func TestMarshal(t *testing.T) { return p }(), want: strings.Repeat(`{"P":`, startDetectingCyclesAfter) + `{"P"`, - wantErr: &SemanticError{action: "marshal", GoType: reflect.TypeOf((*recursivePointer)(nil)), Err: errors.New("encountered a cycle")}, + wantErr: &SemanticError{action: "marshal", GoType: reflect.TypeFor[*recursivePointer](), Err: errors.New("encountered a cycle")}, }, { name: jsontest.Name("Pointers/IgnoreInvalidFormat"), opts: []Options{invalidFormatOption}, diff --git a/arshal_time.go b/arshal_time.go index aad714c..f1ef5ee 100644 --- a/arshal_time.go +++ b/arshal_time.go @@ -22,8 +22,8 @@ import ( ) var ( - timeDurationType = reflect.TypeOf((*time.Duration)(nil)).Elem() - timeTimeType = reflect.TypeOf((*time.Time)(nil)).Elem() + timeDurationType = reflect.TypeFor[time.Duration]() + timeTimeType = reflect.TypeFor[time.Time]() ) func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler { diff --git a/errors_test.go b/errors_test.go index 3e607c1..69efeee 100644 --- a/errors_test.go +++ b/errors_test.go @@ -34,31 +34,31 @@ func TestSemanticError(t *testing.T) { err: &SemanticError{action: "marshal", JSONKind: '"'}, want: "json: cannot marshal JSON string", }, { - err: &SemanticError{GoType: reflect.TypeOf(bool(false))}, + err: &SemanticError{GoType: reflect.TypeFor[bool]()}, want: "json: cannot handle Go value of type bool", }, { - err: &SemanticError{action: "marshal", GoType: reflect.TypeOf(int(0))}, + err: &SemanticError{action: "marshal", GoType: reflect.TypeFor[int]()}, want: "json: cannot marshal Go value of type int", }, { - err: &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(uint(0))}, + err: &SemanticError{action: "unmarshal", GoType: reflect.TypeFor[uint]()}, want: "json: cannot unmarshal Go value of type uint", }, { - err: &SemanticError{JSONKind: '0', GoType: reflect.TypeOf(tar.Header{})}, + err: &SemanticError{JSONKind: '0', GoType: reflect.TypeFor[tar.Header]()}, want: "json: cannot handle JSON number with Go value of type tar.Header", }, { - err: &SemanticError{action: "marshal", JSONKind: '{', GoType: reflect.TypeOf(bytes.Buffer{})}, + err: &SemanticError{action: "marshal", JSONKind: '{', GoType: reflect.TypeFor[bytes.Buffer]()}, want: "json: cannot marshal JSON object from Go value of type bytes.Buffer", }, { - err: &SemanticError{action: "unmarshal", JSONKind: ']', GoType: reflect.TypeOf(strings.Reader{})}, + err: &SemanticError{action: "unmarshal", JSONKind: ']', GoType: reflect.TypeFor[strings.Reader]()}, want: "json: cannot unmarshal JSON array into Go value of type strings.Reader", }, { - err: &SemanticError{action: "unmarshal", JSONKind: '{', GoType: reflect.TypeOf(float64(0)), ByteOffset: 123}, + err: &SemanticError{action: "unmarshal", JSONKind: '{', GoType: reflect.TypeFor[float64](), ByteOffset: 123}, want: "json: cannot unmarshal JSON object into Go value of type float64 after byte offset 123", }, { - err: &SemanticError{action: "marshal", JSONKind: 'f', GoType: reflect.TypeOf(complex128(0)), ByteOffset: 123, JSONPointer: "/foo/2/bar/3"}, + err: &SemanticError{action: "marshal", JSONKind: 'f', GoType: reflect.TypeFor[complex128](), ByteOffset: 123, JSONPointer: "/foo/2/bar/3"}, want: "json: cannot marshal JSON boolean from Go value of type complex128 within JSON value at \"/foo/2/bar/3\"", }, { - err: &SemanticError{action: "unmarshal", JSONKind: '}', GoType: reflect.TypeOf((*io.Reader)(nil)).Elem(), ByteOffset: 123, JSONPointer: "/foo/2/bar/3", Err: errors.New("some underlying error")}, + err: &SemanticError{action: "unmarshal", JSONKind: '}', GoType: reflect.TypeFor[io.Reader](), ByteOffset: 123, JSONPointer: "/foo/2/bar/3", Err: errors.New("some underlying error")}, want: "json: cannot unmarshal JSON object into Go value of type io.Reader within JSON value at \"/foo/2/bar/3\": some underlying error", }, { err: &SemanticError{Err: errors.New("some underlying error")}, diff --git a/fields.go b/fields.go index fbc5e41..9ee166c 100644 --- a/fields.go +++ b/fields.go @@ -24,7 +24,7 @@ type isZeroer interface { IsZero() bool } -var isZeroerType = reflect.TypeOf((*isZeroer)(nil)).Elem() +var isZeroerType = reflect.TypeFor[isZeroer]() type structFields struct { flattened []structField // listed in depth-first ordering diff --git a/fields_test.go b/fields_test.go index f7ce6bb..fe6e241 100644 --- a/fields_test.go +++ b/fields_test.go @@ -197,7 +197,7 @@ func TestMakeStructFields(t *testing.T) { X map[string]jsontext.Value `json:",unknown"` }{}, want: structFields{ - inlinedFallback: &structField{id: 0, index: []int{2}, typ: reflect.TypeOf(map[string]jsontext.Value(nil)), fieldOptions: fieldOptions{name: "X", quotedName: `"X"`, unknown: true}}, + inlinedFallback: &structField{id: 0, index: []int{2}, typ: reflect.TypeFor[map[string]jsontext.Value](), fieldOptions: fieldOptions{name: "X", quotedName: `"X"`, unknown: true}}, }, }, { name: jsontest.Name("InvalidUTF8"), diff --git a/fold_test.go b/fold_test.go index fb68897..43629ee 100644 --- a/fold_test.go +++ b/fold_test.go @@ -120,7 +120,7 @@ func runUnmarshalUnknown(tb testing.TB) { for i := 0; i < n; i++ { fields = append(fields, reflect.StructField{ Name: fmt.Sprintf("Name%d", i), - Type: reflect.TypeOf(0), + Type: reflect.TypeFor[int](), Tag: `json:",nocase"`, }) }