Source File
encode.go
Belonging Package
encoding/json
package json
import (
)
type UnsupportedTypeError struct {
Type reflect.Type
}
func ( *UnsupportedTypeError) () string {
return "json: unsupported type: " + .Type.String()
}
type UnsupportedValueError struct {
Value reflect.Value
Str string
}
func ( *UnsupportedValueError) () string {
return "json: unsupported value: " + .Str
}
type InvalidUTF8Error struct {
S string // the whole string value that caused the error
}
func ( *InvalidUTF8Error) () string {
return "json: invalid UTF-8 in string: " + strconv.Quote(.S)
}
type MarshalerError struct {
Type reflect.Type
Err error
sourceFunc string
}
func ( *MarshalerError) () string {
:= .sourceFunc
if == "" {
= "MarshalJSON"
}
return "json: error calling " + +
" for type " + .Type.String() +
": " + .Err.Error()
}
func ( *MarshalerError) () error { return .Err }
var hex = "0123456789abcdef"
type encodeState struct {
bytes.Buffer // accumulated output
scratch [64]byte
ptrLevel uint
ptrSeen map[interface{}]struct{}
}
const startDetectingCyclesAfter = 1000
var encodeStatePool sync.Pool
func () *encodeState {
if := encodeStatePool.Get(); != nil {
:= .(*encodeState)
.Reset()
if len(.ptrSeen) > 0 {
panic("ptrEncoder.encode should have emptied ptrSeen via defers")
}
.ptrLevel = 0
return
}
return &encodeState{ptrSeen: make(map[interface{}]struct{})}
}
func ( *encodeState) ( error) {
panic(jsonError{})
}
func ( reflect.Value) bool {
switch .Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return .Len() == 0
case reflect.Bool:
return !.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return .Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return .Uint() == 0
case reflect.Float32, reflect.Float64:
return .Float() == 0
case reflect.Interface, reflect.Ptr:
return .IsNil()
}
return false
}
func ( *encodeState) ( reflect.Value, encOpts) {
valueEncoder()(, , )
}
escapeHTML bool
}
type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
var encoderCache sync.Map // map[reflect.Type]encoderFunc
func ( reflect.Value) encoderFunc {
if !.IsValid() {
return invalidValueEncoder
}
return typeEncoder(.Type())
}
func ( reflect.Type) encoderFunc {
if , := encoderCache.Load(); {
return .(encoderFunc)
}
var (
sync.WaitGroup
encoderFunc
)
.Add(1)
, := encoderCache.LoadOrStore(, encoderFunc(func( *encodeState, reflect.Value, encOpts) {
.Wait()
(, , )
}))
if {
return .(encoderFunc)
}
= newTypeEncoder(, true)
.Done()
encoderCache.Store(, )
return
}
var (
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
)
if .Kind() != reflect.Ptr && && reflect.PtrTo().Implements(marshalerType) {
return newCondAddrEncoder(addrMarshalerEncoder, (, false))
}
if .Implements(marshalerType) {
return marshalerEncoder
}
if .Kind() != reflect.Ptr && && reflect.PtrTo().Implements(textMarshalerType) {
return newCondAddrEncoder(addrTextMarshalerEncoder, (, false))
}
if .Implements(textMarshalerType) {
return textMarshalerEncoder
}
switch .Kind() {
case reflect.Bool:
return boolEncoder
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return intEncoder
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return uintEncoder
case reflect.Float32:
return float32Encoder
case reflect.Float64:
return float64Encoder
case reflect.String:
return stringEncoder
case reflect.Interface:
return interfaceEncoder
case reflect.Struct:
return newStructEncoder()
case reflect.Map:
return newMapEncoder()
case reflect.Slice:
return newSliceEncoder()
case reflect.Array:
return newArrayEncoder()
case reflect.Ptr:
return newPtrEncoder()
default:
return unsupportedTypeEncoder
}
}
func ( *encodeState, reflect.Value, encOpts) {
.WriteString("null")
}
func ( *encodeState, reflect.Value, encOpts) {
if .Kind() == reflect.Ptr && .IsNil() {
.WriteString("null")
return
}
, := .Interface().(Marshaler)
if ! {
.WriteString("null")
return
}
, := .MarshalJSON()
= compact(&.Buffer, , .escapeHTML)
}
if != nil {
.error(&MarshalerError{.Type(), , "MarshalJSON"})
}
}
func ( *encodeState, reflect.Value, encOpts) {
:= .Addr()
if .IsNil() {
.WriteString("null")
return
}
:= .Interface().(Marshaler)
, := .MarshalJSON()
= compact(&.Buffer, , .escapeHTML)
}
if != nil {
.error(&MarshalerError{.Type(), , "MarshalJSON"})
}
}
func ( *encodeState, reflect.Value, encOpts) {
if .Kind() == reflect.Ptr && .IsNil() {
.WriteString("null")
return
}
, := .Interface().(encoding.TextMarshaler)
if ! {
.WriteString("null")
return
}
, := .MarshalText()
if != nil {
.error(&MarshalerError{.Type(), , "MarshalText"})
}
.stringBytes(, .escapeHTML)
}
func ( *encodeState, reflect.Value, encOpts) {
:= .Addr()
if .IsNil() {
.WriteString("null")
return
}
:= .Interface().(encoding.TextMarshaler)
, := .MarshalText()
if != nil {
.error(&MarshalerError{.Type(), , "MarshalText"})
}
.stringBytes(, .escapeHTML)
}
func ( *encodeState, reflect.Value, encOpts) {
if .quoted {
.WriteByte('"')
}
if .Bool() {
.WriteString("true")
} else {
.WriteString("false")
}
if .quoted {
.WriteByte('"')
}
}
func ( *encodeState, reflect.Value, encOpts) {
:= strconv.AppendInt(.scratch[:0], .Int(), 10)
if .quoted {
.WriteByte('"')
}
.Write()
if .quoted {
.WriteByte('"')
}
}
func ( *encodeState, reflect.Value, encOpts) {
:= strconv.AppendUint(.scratch[:0], .Uint(), 10)
if .quoted {
.WriteByte('"')
}
.Write()
if .quoted {
.WriteByte('"')
}
}
type floatEncoder int // number of bits
func ( floatEncoder) ( *encodeState, reflect.Value, encOpts) {
:= .Float()
if math.IsInf(, 0) || math.IsNaN() {
.error(&UnsupportedValueError{, strconv.FormatFloat(, 'g', -1, int())})
}
if != 0 {
if == 64 && ( < 1e-6 || >= 1e21) || == 32 && (float32() < 1e-6 || float32() >= 1e21) {
= 'e'
}
}
= strconv.AppendFloat(, , , -1, int())
:= len()
if >= 4 && [-4] == 'e' && [-3] == '-' && [-2] == '0' {
[-2] = [-1]
= [:-1]
}
}
if .quoted {
.WriteByte('"')
}
.Write()
if .quoted {
.WriteByte('"')
}
}
var (
float32Encoder = (floatEncoder(32)).encode
float64Encoder = (floatEncoder(64)).encode
)
func ( *encodeState, reflect.Value, encOpts) {
if .Type() == numberType {
if == "" {
= "0" // Number's zero-val
}
if !isValidNumber() {
.error(fmt.Errorf("json: invalid number literal %q", ))
}
if .quoted {
.WriteByte('"')
}
.WriteString()
if .quoted {
.WriteByte('"')
}
return
}
if .quoted {
.string(.String(), .escapeHTML)
.stringBytes(.Bytes(), false)
encodeStatePool.Put()
} else {
.string(.String(), .escapeHTML)
}
}
if == "" {
return false
}
if [0] == '-' {
= [1:]
if == "" {
return false
}
}
return == ""
}
func ( *encodeState, reflect.Value, encOpts) {
if .IsNil() {
.WriteString("null")
return
}
.reflectValue(.Elem(), )
}
func ( *encodeState, reflect.Value, encOpts) {
.error(&UnsupportedTypeError{.Type()})
}
type structEncoder struct {
fields structFields
}
type structFields struct {
list []field
nameIndex map[string]int
}
func ( structEncoder) ( *encodeState, reflect.Value, encOpts) {
:= byte('{')
:
for := range .fields.list {
:= &.fields.list[]
:=
for , := range .index {
if .Kind() == reflect.Ptr {
if .IsNil() {
continue
}
= .Elem()
}
= .Field()
}
if .omitEmpty && isEmptyValue() {
continue
}
.WriteByte()
= ','
if .escapeHTML {
.WriteString(.nameEscHTML)
} else {
.WriteString(.nameNonEsc)
}
.quoted = .quoted
.encoder(, , )
}
if == '{' {
.WriteString("{}")
} else {
.WriteByte('}')
}
}
func ( reflect.Type) encoderFunc {
:= structEncoder{fields: cachedTypeFields()}
return .encode
}
type mapEncoder struct {
elemEnc encoderFunc
}
func ( mapEncoder) ( *encodeState, reflect.Value, encOpts) {
if .IsNil() {
.WriteString("null")
return
}
:= .MapKeys()
:= make([]reflectWithString, len())
for , := range {
[].v =
if := [].resolve(); != nil {
.error(fmt.Errorf("json: encoding error for type %q: %q", .Type().String(), .Error()))
}
}
sort.Slice(, func(, int) bool { return [].s < [].s })
for , := range {
if > 0 {
.WriteByte(',')
}
.string(.s, .escapeHTML)
.WriteByte(':')
.elemEnc(, .MapIndex(.v), )
}
.WriteByte('}')
.ptrLevel--
}
func ( reflect.Type) encoderFunc {
switch .Key().Kind() {
case reflect.String,
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
default:
if !.Key().Implements(textMarshalerType) {
return unsupportedTypeEncoder
}
}
:= mapEncoder{typeEncoder(.Elem())}
return .encode
}
func ( *encodeState, reflect.Value, encOpts) {
if .IsNil() {
.WriteString("null")
return
}
:= .Bytes()
.WriteByte('"')
:= base64.StdEncoding.EncodedLen(len())
:= .scratch[:]
base64.StdEncoding.Encode(, )
.Write()
:= base64.NewEncoder(base64.StdEncoding, )
.Write()
.Close()
}
.WriteByte('"')
}
type sliceEncoder struct {
arrayEnc encoderFunc
}
func ( sliceEncoder) ( *encodeState, reflect.Value, encOpts) {
if .IsNil() {
.WriteString("null")
return
}
if .Elem().Kind() == reflect.Uint8 {
:= reflect.PtrTo(.Elem())
if !.Implements(marshalerType) && !.Implements(textMarshalerType) {
return encodeByteSlice
}
}
:= sliceEncoder{newArrayEncoder()}
return .encode
}
type arrayEncoder struct {
elemEnc encoderFunc
}
func ( arrayEncoder) ( *encodeState, reflect.Value, encOpts) {
.WriteByte('[')
:= .Len()
for := 0; < ; ++ {
if > 0 {
.WriteByte(',')
}
.elemEnc(, .Index(), )
}
.WriteByte(']')
}
func ( reflect.Type) encoderFunc {
:= arrayEncoder{typeEncoder(.Elem())}
return .encode
}
type ptrEncoder struct {
elemEnc encoderFunc
}
func ( ptrEncoder) ( *encodeState, reflect.Value, encOpts) {
if .IsNil() {
.WriteString("null")
return
}
:= .Interface()
if , := .ptrSeen[]; {
.error(&UnsupportedValueError{, fmt.Sprintf("encountered a cycle via %s", .Type())})
}
.ptrSeen[] = struct{}{}
defer delete(.ptrSeen, )
}
.elemEnc(, .Elem(), )
.ptrLevel--
}
func ( reflect.Type) encoderFunc {
:= ptrEncoder{typeEncoder(.Elem())}
return .encode
}
type condAddrEncoder struct {
canAddrEnc, elseEnc encoderFunc
}
func ( condAddrEncoder) ( *encodeState, reflect.Value, encOpts) {
if .CanAddr() {
.canAddrEnc(, , )
} else {
.elseEnc(, , )
}
}
func (, encoderFunc) encoderFunc {
:= condAddrEncoder{canAddrEnc: , elseEnc: }
return .encode
}
func ( string) bool {
if == "" {
return false
}
for , := range {
switch {
case !unicode.IsLetter() && !unicode.IsDigit():
return false
}
}
return true
}
func ( reflect.Type, []int) reflect.Type {
for , := range {
if .Kind() == reflect.Ptr {
= .Elem()
}
= .Field().Type
}
return
}
type reflectWithString struct {
v reflect.Value
s string
}
func ( *reflectWithString) () error {
if .v.Kind() == reflect.String {
.s = .v.String()
return nil
}
if , := .v.Interface().(encoding.TextMarshaler); {
if .v.Kind() == reflect.Ptr && .v.IsNil() {
return nil
}
, := .MarshalText()
.s = string()
return
}
switch .v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
.s = strconv.FormatInt(.v.Int(), 10)
return nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
.s = strconv.FormatUint(.v.Uint(), 10)
return nil
}
panic("unexpected map key type")
}
func ( *encodeState) ( string, bool) {
.WriteByte('"')
:= 0
for := 0; < len(); {
if := []; < utf8.RuneSelf {
if htmlSafeSet[] || (! && safeSet[]) {
++
continue
}
if < {
.WriteString([:])
}
.WriteByte('\\')
switch {
case '\\', '"':
.WriteByte()
case '\n':
.WriteByte('n')
case '\r':
.WriteByte('r')
case '\t':
.WriteByte('t')
.WriteString(`u00`)
.WriteByte(hex[>>4])
.WriteByte(hex[&0xF])
}
++
=
continue
}
, := utf8.DecodeRuneInString([:])
if == utf8.RuneError && == 1 {
if < {
.WriteString([:])
}
.WriteString(`\ufffd`)
+=
=
continue
if == '\u2028' || == '\u2029' {
if < {
.WriteString([:])
}
.WriteString(`\u202`)
.WriteByte(hex[&0xF])
+=
=
continue
}
+=
}
if < len() {
.WriteString([:])
}
.WriteByte('"')
}
func ( *encodeState) ( []byte, bool) {
.WriteByte('"')
:= 0
for := 0; < len(); {
if := []; < utf8.RuneSelf {
if htmlSafeSet[] || (! && safeSet[]) {
++
continue
}
if < {
.Write([:])
}
.WriteByte('\\')
switch {
case '\\', '"':
.WriteByte()
case '\n':
.WriteByte('n')
case '\r':
.WriteByte('r')
case '\t':
.WriteByte('t')
.WriteString(`u00`)
.WriteByte(hex[>>4])
.WriteByte(hex[&0xF])
}
++
=
continue
}
, := utf8.DecodeRune([:])
if == utf8.RuneError && == 1 {
if < {
.Write([:])
}
.WriteString(`\ufffd`)
+=
=
continue
type field struct {
name string
nameBytes []byte // []byte(name)
equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
nameNonEsc string // `"` + name + `":`
nameEscHTML string // `"` + HTMLEscape(name) + `":`
tag bool
index []int
typ reflect.Type
omitEmpty bool
quoted bool
encoder encoderFunc
}
var []field
continue
= .Elem()
}
.Reset()
.WriteString(`"`)
HTMLEscape(&, .nameBytes)
.WriteString(`":`)
.nameEscHTML = .String()
.nameNonEsc = `"` + .name + `":`
= append(, )
:= [:0]
:= []
:= .name
for = 1; + < len(); ++ {
:= [+]
if .name != {
break
}
}
if == 1 { // Only one field with this name
= append(, )
continue
}
, := dominantField([ : +])
if {
= append(, )
}
}
=
sort.Sort(byIndex())
for := range {
:= &[]
.encoder = typeEncoder(typeByIndex(, .index))
}
:= make(map[string]int, len())
for , := range {
[.name] =
}
return structFields{, }
}
func ( reflect.Type) structFields {
if , := fieldCache.Load(); {
return .(structFields)
}
, := fieldCache.LoadOrStore(, typeFields())
return .(structFields)
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |