Last active
October 22, 2026 22:45
-
-
Save aktau/6d191f0feb08825483a39b3d40fb214d to your computer and use it in GitHub Desktop.
json arshal: typeassert + comma-overwrite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package go852725 | |
| import ( | |
| "math" | |
| "reflect" | |
| "strconv" | |
| ) | |
| // Full TypeAssert + Generics implementation for encoding/json/v2/arshal_default.go. | |
| // Replace *Flags -> *jsonflags.Flags, FormatNilSliceAsNull -> jsonflags.FormatNilSliceAsNull, | |
| // appendQuote -> jsonwire.AppendQuote, and appendFloat -> jsonwire.AppendFloat. | |
| // isSimpleType reports whether values of t can be marshaled by appendSimple. | |
| // This is the case for scalars without custom marshaling and unnamed slices | |
| // of unnamed scalars. | |
| func isSimpleType(t reflect.Type) bool { | |
| if t.Kind() == reflect.Slice { | |
| // Require unnamed slice and unnamed element so reflect.TypeAssert[[]T] | |
| // is guaranteed to match and neither type can have custom marshaling methods. | |
| // A []byte is marshaled as a base64 string, not as a JSON array. | |
| elem := t.Elem() | |
| return t.PkgPath() == "" && elem.PkgPath() == "" && | |
| elem.Kind() != reflect.Uint8 && isScalarKind(elem.Kind()) | |
| } | |
| return isScalarKind(t.Kind()) // in json/v2: && !lookupMarshaler(t).nonDefault | |
| } | |
| // isScalarKind reports whether k is a kind handled by appendScalar. | |
| func isScalarKind(k reflect.Kind) bool { | |
| switch k { | |
| case reflect.Bool, reflect.String, | |
| reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, | |
| reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, | |
| reflect.Float32, reflect.Float64: | |
| return true | |
| } | |
| return false | |
| } | |
| // appendSimple appends the default JSON representation of v to b, | |
| // where v is a scalar or an unnamed slice of unnamed scalars (see isSimpleType). | |
| // It reports false if v cannot be handled by this fast path, | |
| // in which case the caller must fall back to the regular marshaler. | |
| func appendSimple(b []byte, v reflect.Value, flags *Flags) ([]byte, bool) { | |
| if v.Kind() != reflect.Slice { | |
| return appendScalar(b, v, flags) | |
| } | |
| if v.IsNil() && flags.Get(FormatNilSliceAsNull) { | |
| return append(b, "null"...), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]string](v); ok { | |
| return appendStringSlice(b, s, flags) | |
| } | |
| if s, ok := reflect.TypeAssert[[]int](v); ok { | |
| return appendIntSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]int64](v); ok { | |
| return appendIntSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]float64](v); ok { | |
| return appendFloatSlice(b, s, 64) | |
| } | |
| if s, ok := reflect.TypeAssert[[]bool](v); ok { | |
| return appendBoolSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]int32](v); ok { | |
| return appendIntSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]uint](v); ok { | |
| return appendUintSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]uint64](v); ok { | |
| return appendUintSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]uint32](v); ok { | |
| return appendUintSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]float32](v); ok { | |
| return appendFloatSlice(b, s, 32) | |
| } | |
| if s, ok := reflect.TypeAssert[[]int16](v); ok { | |
| return appendIntSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]int8](v); ok { | |
| return appendIntSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]uint16](v); ok { | |
| return appendUintSlice(b, s), true | |
| } | |
| if s, ok := reflect.TypeAssert[[]uintptr](v); ok { | |
| return appendUintSlice(b, s), true | |
| } | |
| return b, false | |
| } | |
| // appendScalar appends the default JSON representation of a scalar v to b, | |
| // assuming that StringifyNumbers is not set. | |
| // It reports false if v cannot be handled by this fast path | |
| // (e.g., due to non-finite floats or invalid UTF-8), | |
| // in which case the caller must fall back to the regular marshaler. | |
| func appendScalar(b []byte, v reflect.Value, flags *Flags) ([]byte, bool) { | |
| switch v.Kind() { | |
| case reflect.Bool: | |
| return strconv.AppendBool(b, v.Bool()), true | |
| case reflect.String: | |
| b, err := appendQuote(b, []byte(v.String()), flags) | |
| return b, err == nil | |
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |
| return strconv.AppendInt(b, v.Int(), 10), true | |
| case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | |
| return strconv.AppendUint(b, v.Uint(), 10), true | |
| case reflect.Float32, reflect.Float64: | |
| bits := 64 | |
| if v.Kind() == reflect.Float32 { | |
| bits = 32 | |
| } | |
| if fv := v.Float(); !math.IsNaN(fv) && !math.IsInf(fv, 0) { | |
| return appendFloat(b, fv, bits), true | |
| } | |
| } | |
| return b, false | |
| } | |
| func appendBoolSlice(b []byte, s []bool) []byte { | |
| if len(s) == 0 { | |
| return append(b, "[]"...) | |
| } | |
| b = append(b, '[') | |
| for _, x := range s { | |
| b = strconv.AppendBool(b, x) | |
| b = append(b, ',') | |
| } | |
| b[len(b)-1] = ']' | |
| return b | |
| } | |
| func appendStringSlice(b []byte, s []string, flags *Flags) ([]byte, bool) { | |
| if len(s) == 0 { | |
| return append(b, "[]"...), true | |
| } | |
| b = append(b, '[') | |
| for _, x := range s { | |
| var err error | |
| if b, err = appendQuote(b, []byte(x), flags); err != nil { | |
| return b, false | |
| } | |
| b = append(b, ',') | |
| } | |
| b[len(b)-1] = ']' | |
| return b, true | |
| } | |
| func appendIntSlice[T ~int | ~int8 | ~int16 | ~int32 | ~int64](b []byte, s []T) []byte { | |
| if len(s) == 0 { | |
| return append(b, "[]"...) | |
| } | |
| b = append(b, '[') | |
| for _, x := range s { | |
| b = strconv.AppendInt(b, int64(x), 10) | |
| b = append(b, ',') | |
| } | |
| b[len(b)-1] = ']' | |
| return b | |
| } | |
| func appendUintSlice[T ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr](b []byte, s []T) []byte { | |
| if len(s) == 0 { | |
| return append(b, "[]"...) | |
| } | |
| b = append(b, '[') | |
| for _, x := range s { | |
| b = strconv.AppendUint(b, uint64(x), 10) | |
| b = append(b, ',') | |
| } | |
| b[len(b)-1] = ']' | |
| return b | |
| } | |
| func appendFloatSlice[T ~float32 | ~float64](b []byte, s []T, bits int) ([]byte, bool) { | |
| if len(s) == 0 { | |
| return append(b, "[]"...), true | |
| } | |
| b = append(b, '[') | |
| for _, x := range s { | |
| fv := float64(x) | |
| if math.IsNaN(fv) || math.IsInf(fv, 0) { | |
| return b, false | |
| } | |
| b = appendFloat(b, fv, bits) | |
| b = append(b, ',') | |
| } | |
| b[len(b)-1] = ']' | |
| return b, true | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment