// Copyright 2010 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// Package json implements encoding and decoding of JSON as defined in// RFC 7159. The mapping between JSON and Go values is described// in the documentation for the Marshal and Unmarshal functions.//// See "JSON and Go" for an introduction to this package:// https://golang.org/doc/articles/json_and_go.html
package jsonimport ()// Marshal returns the JSON encoding of v.//// Marshal traverses the value v recursively.// If an encountered value implements the Marshaler interface// and is not a nil pointer, Marshal calls its MarshalJSON method// to produce JSON. If no MarshalJSON method is present but the// value implements encoding.TextMarshaler instead, Marshal calls// its MarshalText method and encodes the result as a JSON string.// The nil pointer exception is not strictly necessary// but mimics a similar, necessary exception in the behavior of// UnmarshalJSON.//// Otherwise, Marshal uses the following type-dependent default encodings://// Boolean values encode as JSON booleans.//// Floating point, integer, and Number values encode as JSON numbers.//// String values encode as JSON strings coerced to valid UTF-8,// replacing invalid bytes with the Unicode replacement rune.// So that the JSON will be safe to embed inside HTML <script> tags,// the string is encoded using HTMLEscape,// which replaces "<", ">", "&", U+2028, and U+2029 are escaped// to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029".// This replacement can be disabled when using an Encoder,// by calling SetEscapeHTML(false).//// Array and slice values encode as JSON arrays, except that// []byte encodes as a base64-encoded string, and a nil slice// encodes as the null JSON value.//// Struct values encode as JSON objects.// Each exported struct field becomes a member of the object, using the// field name as the object key, unless the field is omitted for one of the// reasons given below.//// The encoding of each struct field can be customized by the format string// stored under the "json" key in the struct field's tag.// The format string gives the name of the field, possibly followed by a// comma-separated list of options. The name may be empty in order to// specify options without overriding the default field name.//// The "omitempty" option specifies that the field should be omitted// from the encoding if the field has an empty value, defined as// false, 0, a nil pointer, a nil interface value, and any empty array,// slice, map, or string.//// As a special case, if the field tag is "-", the field is always omitted.// Note that a field with name "-" can still be generated using the tag "-,".//// Examples of struct field tags and their meanings://// // Field appears in JSON as key "myName".// Field int `json:"myName"`//// // Field appears in JSON as key "myName" and// // the field is omitted from the object if its value is empty,// // as defined above.// Field int `json:"myName,omitempty"`//// // Field appears in JSON as key "Field" (the default), but// // the field is skipped if empty.// // Note the leading comma.// Field int `json:",omitempty"`//// // Field is ignored by this package.// Field int `json:"-"`//// // Field appears in JSON as key "-".// Field int `json:"-,"`//// The "string" option signals that a field is stored as JSON inside a// JSON-encoded string. It applies only to fields of string, floating point,// integer, or boolean types. This extra level of encoding is sometimes used// when communicating with JavaScript programs://// Int64String int64 `json:",string"`//// The key name will be used if it's a non-empty string consisting of// only Unicode letters, digits, and ASCII punctuation except quotation// marks, backslash, and comma.//// Anonymous struct fields are usually marshaled as if their inner exported fields// were fields in the outer struct, subject to the usual Go visibility rules amended// as described in the next paragraph.// An anonymous struct field with a name given in its JSON tag is treated as// having that name, rather than being anonymous.// An anonymous struct field of interface type is treated the same as having// that type as its name, rather than being anonymous.//// The Go visibility rules for struct fields are amended for JSON when// deciding which field to marshal or unmarshal. If there are// multiple fields at the same level, and that level is the least// nested (and would therefore be the nesting level selected by the// usual Go rules), the following extra rules apply://// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,// even if there are multiple untagged fields that would otherwise conflict.//// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.//// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.//// Handling of anonymous struct fields is new in Go 1.1.// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of// an anonymous struct field in both current and earlier versions, give the field// a JSON tag of "-".//// Map values encode as JSON objects. The map's key type must either be a// string, an integer type, or implement encoding.TextMarshaler. The map keys// are sorted and used as JSON object keys by applying the following rules,// subject to the UTF-8 coercion described for string values above:// - keys of any string type are used directly// - encoding.TextMarshalers are marshaled// - integer keys are converted to strings//// Pointer values encode as the value pointed to.// A nil pointer encodes as the null JSON value.//// Interface values encode as the value contained in the interface.// A nil interface value encodes as the null JSON value.//// Channel, complex, and function values cannot be encoded in JSON.// Attempting to encode such a value causes Marshal to return// an UnsupportedTypeError.//// JSON cannot represent cyclic data structures and Marshal does not// handle them. Passing cyclic structures to Marshal will result in// an error.func ( any) ([]byte, error) { := newEncodeState()deferencodeStatePool.Put() := .marshal(, encOpts{escapeHTML: true})if != nil {returnnil, } := append([]byte(nil), .Bytes()...)return , nil}// MarshalIndent is like Marshal but applies Indent to format the output.// Each JSON element in the output will begin on a new line beginning with prefix// followed by one or more copies of indent according to the indentation nesting.func ( any, , string) ([]byte, error) { , := Marshal()if != nil {returnnil, }varbytes.Buffer = Indent(&, , , )if != nil {returnnil, }return .Bytes(), nil}// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029// so that the JSON will be safe to embed inside HTML <script> tags.// For historical reasons, web browsers don't honor standard HTML// escaping within <script> tags, so an alternative JSON encoding must// be used.func ( *bytes.Buffer, []byte) {// The characters can only appear in string literals, // so just scan the string one byte at a time. := 0for , := range {if == '<' || == '>' || == '&' {if < { .Write([:]) } .WriteString(`\u00`) .WriteByte(hex[>>4]) .WriteByte(hex[&0xF]) = + 1 }// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).if == 0xE2 && +2 < len() && [+1] == 0x80 && [+2]&^1 == 0xA8 {if < { .Write([:]) } .WriteString(`\u202`) .WriteByte(hex[[+2]&0xF]) = + 3 } }if < len() { .Write([:]) }}// Marshaler is the interface implemented by types that// can marshal themselves into valid JSON.typeMarshalerinterface {MarshalJSON() ([]byte, error)}// An UnsupportedTypeError is returned by Marshal when attempting// to encode an unsupported value type.typeUnsupportedTypeErrorstruct { Type reflect.Type}func ( *UnsupportedTypeError) () string {return"json: unsupported type: " + .Type.String()}// An UnsupportedValueError is returned by Marshal when attempting// to encode an unsupported value.typeUnsupportedValueErrorstruct { Value reflect.Value Str string}func ( *UnsupportedValueError) () string {return"json: unsupported value: " + .Str}// Before Go 1.2, an InvalidUTF8Error was returned by Marshal when// attempting to encode a string value with invalid UTF-8 sequences.// As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by// replacing invalid bytes with the Unicode replacement rune U+FFFD.//// Deprecated: No longer used; kept for compatibility.typeInvalidUTF8Errorstruct { S string// the whole string value that caused the error}func ( *InvalidUTF8Error) () string {return"json: invalid UTF-8 in string: " + strconv.Quote(.S)}// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method.typeMarshalerErrorstruct { Type reflect.Type Err error sourceFunc string}func ( *MarshalerError) () string { := .sourceFuncif == "" { = "MarshalJSON" }return"json: error calling " + +" for type " + .Type.String() +": " + .Err.Error()}// Unwrap returns the underlying error.func ( *MarshalerError) () error { return .Err }var hex = "0123456789abcdef"// An encodeState encodes JSON into a bytes.Buffer.type encodeState struct {bytes.Buffer// accumulated output scratch [64]byte// Keep track of what pointers we've seen in the current recursive call // path, to avoid cycles that could lead to a stack overflow. Only do // the relatively expensive map operations if ptrLevel is larger than // startDetectingCyclesAfter, so that we skip the work if we're within a // reasonable amount of nested pointers deep. ptrLevel uint ptrSeen map[any]struct{}}const startDetectingCyclesAfter = 1000var encodeStatePool sync.Poolfunc newEncodeState() *encodeState {if := encodeStatePool.Get(); != nil { := .(*encodeState) .Reset()iflen(.ptrSeen) > 0 {panic("ptrEncoder.encode should have emptied ptrSeen via defers") } .ptrLevel = 0return }return &encodeState{ptrSeen: make(map[any]struct{})}}// jsonError is an error wrapper type for internal use only.// Panics with errors are wrapped in jsonError so that the top-level recover// can distinguish intentional panics from this package.type jsonError struct{ error }func ( *encodeState) ( any, encOpts) ( error) {deferfunc() {if := recover(); != nil {if , := .(jsonError); { = .error } else {panic() } } }() .reflectValue(reflect.ValueOf(), )returnnil}// error aborts the encoding by panicking with err wrapped in jsonError.func ( *encodeState) ( error) {panic(jsonError{})}func isEmptyValue( reflect.Value) bool {switch .Kind() {casereflect.Array, reflect.Map, reflect.Slice, reflect.String:return .Len() == 0casereflect.Bool:return !.Bool()casereflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:return .Int() == 0casereflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:return .Uint() == 0casereflect.Float32, reflect.Float64:return .Float() == 0casereflect.Interface, reflect.Pointer:return .IsNil() }returnfalse}func ( *encodeState) ( reflect.Value, encOpts) {valueEncoder()(, , )}type encOpts struct {// quoted causes primitive fields to be encoded inside JSON strings. quoted bool// escapeHTML causes '<', '>', and '&' to be escaped in JSON strings. escapeHTML bool}type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)var encoderCache sync.Map// map[reflect.Type]encoderFuncfunc valueEncoder( reflect.Value) encoderFunc {if !.IsValid() {returninvalidValueEncoder }returntypeEncoder(.Type())}func typeEncoder( reflect.Type) encoderFunc {if , := encoderCache.Load(); {return .(encoderFunc) }// To deal with recursive types, populate the map with an // indirect func before we build it. This type waits on the // real func (f) to be ready and then calls it. This indirect // func is only used for recursive types.var (sync.WaitGroupencoderFunc ) .Add(1) , := encoderCache.LoadOrStore(, encoderFunc(func( *encodeState, reflect.Value, encOpts) { .Wait() (, , ) }))if {return .(encoderFunc) }// Compute the real encoder and replace the indirect func with it. = newTypeEncoder(, true) .Done()encoderCache.Store(, )return}var ( marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem())// newTypeEncoder constructs an encoderFunc for a type.// The returned encoder only checks CanAddr when allowAddr is true.func newTypeEncoder( reflect.Type, bool) encoderFunc {// If we have a non-pointer value whose type implements // Marshaler with a value receiver, then we're better off taking // the address of the value - otherwise we end up with an // allocation as we cast the value to an interface.if .Kind() != reflect.Pointer && && reflect.PointerTo().Implements(marshalerType) {returnnewCondAddrEncoder(addrMarshalerEncoder, (, false)) }if .Implements(marshalerType) {returnmarshalerEncoder }if .Kind() != reflect.Pointer && && reflect.PointerTo().Implements(textMarshalerType) {returnnewCondAddrEncoder(addrTextMarshalerEncoder, (, false)) }if .Implements(textMarshalerType) {returntextMarshalerEncoder }switch .Kind() {casereflect.Bool:returnboolEncodercasereflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:returnintEncodercasereflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:returnuintEncodercasereflect.Float32:returnfloat32Encodercasereflect.Float64:returnfloat64Encodercasereflect.String:returnstringEncodercasereflect.Interface:returninterfaceEncodercasereflect.Struct:returnnewStructEncoder()casereflect.Map:returnnewMapEncoder()casereflect.Slice:returnnewSliceEncoder()casereflect.Array:returnnewArrayEncoder()casereflect.Pointer:returnnewPtrEncoder()default:returnunsupportedTypeEncoder }}func invalidValueEncoder( *encodeState, reflect.Value, encOpts) { .WriteString("null")}func marshalerEncoder( *encodeState, reflect.Value, encOpts) {if .Kind() == reflect.Pointer && .IsNil() { .WriteString("null")return } , := .Interface().(Marshaler)if ! { .WriteString("null")return } , := .MarshalJSON()if == nil {// copy JSON into buffer, checking validity. = compact(&.Buffer, , .escapeHTML) }if != nil { .error(&MarshalerError{.Type(), , "MarshalJSON"}) }}func addrMarshalerEncoder( *encodeState, reflect.Value, encOpts) { := .Addr()if .IsNil() { .WriteString("null")return } := .Interface().(Marshaler) , := .MarshalJSON()if == nil {// copy JSON into buffer, checking validity. = compact(&.Buffer, , .escapeHTML) }if != nil { .error(&MarshalerError{.Type(), , "MarshalJSON"}) }}func textMarshalerEncoder( *encodeState, reflect.Value, encOpts) {if .Kind() == reflect.Pointer && .IsNil() { .WriteString("null")return } , := .Interface().(encoding.TextMarshaler)if ! { .WriteString("null")return } , := .MarshalText()if != nil { .error(&MarshalerError{.Type(), , "MarshalText"}) } .stringBytes(, .escapeHTML)}func addrTextMarshalerEncoder( *encodeState, reflect.Value, encOpts) { := .Addr()if .IsNil() { .WriteString("null")return } := .Interface().(encoding.TextMarshaler) , := .MarshalText()if != nil { .error(&MarshalerError{.Type(), , "MarshalText"}) } .stringBytes(, .escapeHTML)}func boolEncoder( *encodeState, reflect.Value, encOpts) {if .quoted { .WriteByte('"') }if .Bool() { .WriteString("true") } else { .WriteString("false") }if .quoted { .WriteByte('"') }}func intEncoder( *encodeState, reflect.Value, encOpts) { := strconv.AppendInt(.scratch[:0], .Int(), 10)if .quoted { .WriteByte('"') } .Write()if .quoted { .WriteByte('"') }}func uintEncoder( *encodeState, reflect.Value, encOpts) { := strconv.AppendUint(.scratch[:0], .Uint(), 10)if .quoted { .WriteByte('"') } .Write()if .quoted { .WriteByte('"') }}type floatEncoder int// number of bitsfunc ( floatEncoder) ( *encodeState, reflect.Value, encOpts) { := .Float()ifmath.IsInf(, 0) || math.IsNaN() { .error(&UnsupportedValueError{, strconv.FormatFloat(, 'g', -1, int())}) }// Convert as if by ES6 number to string conversion. // This matches most other JSON generators. // See golang.org/issue/6384 and golang.org/issue/14135. // Like fmt %g, but the exponent cutoffs are different // and exponents themselves are not padded to two digits. := .scratch[:0] := math.Abs() := byte('f')// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.if != 0 {if == 64 && ( < 1e-6 || >= 1e21) || == 32 && (float32() < 1e-6 || float32() >= 1e21) { = 'e' } } = strconv.AppendFloat(, , , -1, int())if == 'e' {// clean up e-09 to e-9 := 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 stringEncoder( *encodeState, reflect.Value, encOpts) {if .Type() == numberType { := .String()// In Go1.5 the empty string encodes to "0", while this is not a valid number literal // we keep compatibility so check validity after this.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 { := newEncodeState()// Since we encode the string twice, we only need to escape HTML // the first time. .string(.String(), .escapeHTML) .stringBytes(.Bytes(), false)encodeStatePool.Put() } else { .string(.String(), .escapeHTML) }}// isValidNumber reports whether s is a valid JSON number literal.func isValidNumber( string) bool {// This function implements the JSON numbers grammar. // See https://tools.ietf.org/html/rfc7159#section-6 // and https://www.json.org/img/number.pngif == "" {returnfalse }// Optional -if [0] == '-' { = [1:]if == "" {returnfalse } }// Digitsswitch {default:returnfalsecase [0] == '0': = [1:]case'1' <= [0] && [0] <= '9': = [1:]forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] } }// . followed by 1 or more digits.iflen() >= 2 && [0] == '.' && '0' <= [1] && [1] <= '9' { = [2:]forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] } }// e or E followed by an optional - or + and // 1 or more digits.iflen() >= 2 && ([0] == 'e' || [0] == 'E') { = [1:]if [0] == '+' || [0] == '-' { = [1:]if == "" {returnfalse } }forlen() > 0 && '0' <= [0] && [0] <= '9' { = [1:] } }// Make sure we are at the end.return == ""}func interfaceEncoder( *encodeState, reflect.Value, encOpts) {if .IsNil() { .WriteString("null")return } .reflectValue(.Elem(), )}func unsupportedTypeEncoder( *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[]// Find the nested struct field by following f.index. := for , := range .index {if .Kind() == reflect.Pointer {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 newStructEncoder( reflect.Type) encoderFunc { := structEncoder{fields: cachedTypeFields()}return .encode}type mapEncoder struct { elemEnc encoderFunc}func ( mapEncoder) ( *encodeState, reflect.Value, encOpts) {if .IsNil() { .WriteString("null")return }if .ptrLevel++; .ptrLevel > startDetectingCyclesAfter {// We're a large number of nested ptrEncoder.encode calls deep; // start checking if we've run into a pointer cycle. := .UnsafePointer()if , := .ptrSeen[]; { .error(&UnsupportedValueError{, fmt.Sprintf("encountered a cycle via %s", .Type())}) } .ptrSeen[] = struct{}{}deferdelete(.ptrSeen, ) } .WriteByte('{')// Extract and sort the keys. := make([]reflectWithString, .Len()) := .MapRange()for := 0; .Next(); ++ { [].k = .Key() [].v = .Value()if := [].resolve(); != nil { .error(fmt.Errorf("json: encoding error for type %q: %q", .Type().String(), .Error())) } }sort.Slice(, func(, int) bool { return [].ks < [].ks })for , := range {if > 0 { .WriteByte(',') } .string(.ks, .escapeHTML) .WriteByte(':') .elemEnc(, .v, ) } .WriteByte('}') .ptrLevel--}func newMapEncoder( reflect.Type) encoderFunc {switch .Key().Kind() {casereflect.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) {returnunsupportedTypeEncoder } } := mapEncoder{typeEncoder(.Elem())}return .encode}func encodeByteSlice( *encodeState, reflect.Value, encOpts) {if .IsNil() { .WriteString("null")return } := .Bytes() .WriteByte('"') := base64.StdEncoding.EncodedLen(len())if <= len(.scratch) {// If the encoded bytes fit in e.scratch, avoid an extra // allocation and use the cheaper Encoding.Encode. := .scratch[:]base64.StdEncoding.Encode(, ) .Write() } elseif <= 1024 {// The encoded bytes are short enough to allocate for, and // Encoding.Encode is still cheaper. := make([]byte, )base64.StdEncoding.Encode(, ) .Write() } else {// The encoded bytes are too long to cheaply allocate, and // Encoding.Encode is no longer noticeably cheaper. := base64.NewEncoder(base64.StdEncoding, ) .Write() .Close() } .WriteByte('"')}// sliceEncoder just wraps an arrayEncoder, checking to make sure the value isn't nil.type sliceEncoder struct { arrayEnc encoderFunc}func ( sliceEncoder) ( *encodeState, reflect.Value, encOpts) {if .IsNil() { .WriteString("null")return }if .ptrLevel++; .ptrLevel > startDetectingCyclesAfter {// We're a large number of nested ptrEncoder.encode calls deep; // start checking if we've run into a pointer cycle. // Here we use a struct to memorize the pointer to the first element of the slice // and its length. := struct {interface{} // always an unsafe.Pointer, but avoids a dependency on package unsafeint }{.UnsafePointer(), .Len()}if , := .ptrSeen[]; { .error(&UnsupportedValueError{, fmt.Sprintf("encountered a cycle via %s", .Type())}) } .ptrSeen[] = struct{}{}deferdelete(.ptrSeen, ) } .arrayEnc(, , ) .ptrLevel--}func newSliceEncoder( reflect.Type) encoderFunc {// Byte slices get special treatment; arrays don't.if .Elem().Kind() == reflect.Uint8 { := reflect.PointerTo(.Elem())if !.Implements(marshalerType) && !.Implements(textMarshalerType) {returnencodeByteSlice } } := 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 newArrayEncoder( reflect.Type) encoderFunc { := arrayEncoder{typeEncoder(.Elem())}return .encode}type ptrEncoder struct { elemEnc encoderFunc}func ( ptrEncoder) ( *encodeState, reflect.Value, encOpts) {if .IsNil() { .WriteString("null")return }if .ptrLevel++; .ptrLevel > startDetectingCyclesAfter {// We're a large number of nested ptrEncoder.encode calls deep; // start checking if we've run into a pointer cycle. := .Interface()if , := .ptrSeen[]; { .error(&UnsupportedValueError{, fmt.Sprintf("encountered a cycle via %s", .Type())}) } .ptrSeen[] = struct{}{}deferdelete(.ptrSeen, ) } .elemEnc(, .Elem(), ) .ptrLevel--}func newPtrEncoder( 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(, , ) }}// newCondAddrEncoder returns an encoder that checks whether its value// CanAddr and delegates to canAddrEnc if so, else to elseEnc.func newCondAddrEncoder(, encoderFunc) encoderFunc { := condAddrEncoder{canAddrEnc: , elseEnc: }return .encode}func isValidTag( string) bool {if == "" {returnfalse }for , := range {switch {casestrings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", ):// Backslash and quote chars are reserved, but // otherwise any punctuation chars are allowed // in a tag name.case !unicode.IsLetter() && !unicode.IsDigit():returnfalse } }returntrue}func typeByIndex( reflect.Type, []int) reflect.Type {for , := range {if .Kind() == reflect.Pointer { = .Elem() } = .Field().Type }return}type reflectWithString struct { k reflect.Value v reflect.Value ks string}func ( *reflectWithString) () error {if .k.Kind() == reflect.String { .ks = .k.String()returnnil }if , := .k.Interface().(encoding.TextMarshaler); {if .k.Kind() == reflect.Pointer && .k.IsNil() {returnnil } , := .MarshalText() .ks = string()return }switch .k.Kind() {casereflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: .ks = strconv.FormatInt(.k.Int(), 10)returnnilcasereflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: .ks = strconv.FormatUint(.k.Uint(), 10)returnnil }panic("unexpected map key type")}// NOTE: keep in sync with stringBytes below.func ( *encodeState) ( string, bool) { .WriteByte('"') := 0for := 0; < len(); {if := []; < utf8.RuneSelf {ifhtmlSafeSet[] || (! && safeSet[]) { ++continue }if < { .WriteString([:]) } .WriteByte('\\')switch {case'\\', '"': .WriteByte()case'\n': .WriteByte('n')case'\r': .WriteByte('r')case'\t': .WriteByte('t')default:// This encodes bytes < 0x20 except for \t, \n and \r. // If escapeHTML is set, it also escapes <, >, and & // because they can lead to security holes when // user-controlled strings are rendered into JSON // and served to some browsers. .WriteString(`u00`) .WriteByte(hex[>>4]) .WriteByte(hex[&0xF]) } ++ = continue } , := utf8.DecodeRuneInString([:])if == utf8.RuneError && == 1 {if < { .WriteString([:]) } .WriteString(`\ufffd`) += = continue }// U+2028 is LINE SEPARATOR. // U+2029 is PARAGRAPH SEPARATOR. // They are both technically valid characters in JSON strings, // but don't work in JSONP, which has to be evaluated as JavaScript, // and can lead to security holes there. It is valid JSON to // escape them, so we do so unconditionally. // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.if == '\u2028' || == '\u2029' {if < { .WriteString([:]) } .WriteString(`\u202`) .WriteByte(hex[&0xF]) += = continue } += }if < len() { .WriteString([:]) } .WriteByte('"')}// NOTE: keep in sync with string above.func ( *encodeState) ( []byte, bool) { .WriteByte('"') := 0for := 0; < len(); {if := []; < utf8.RuneSelf {ifhtmlSafeSet[] || (! && safeSet[]) { ++continue }if < { .Write([:]) } .WriteByte('\\')switch {case'\\', '"': .WriteByte()case'\n': .WriteByte('n')case'\r': .WriteByte('r')case'\t': .WriteByte('t')default:// This encodes bytes < 0x20 except for \t, \n and \r. // If escapeHTML is set, it also escapes <, >, and & // because they can lead to security holes when // user-controlled strings are rendered into JSON // and served to some browsers. .WriteString(`u00`) .WriteByte(hex[>>4]) .WriteByte(hex[&0xF]) } ++ = continue } , := utf8.DecodeRune([:])if == utf8.RuneError && == 1 {if < { .Write([:]) } .WriteString(`\ufffd`) += = continue }// U+2028 is LINE SEPARATOR. // U+2029 is PARAGRAPH SEPARATOR. // They are both technically valid characters in JSON strings, // but don't work in JSONP, which has to be evaluated as JavaScript, // and can lead to security holes there. It is valid JSON to // escape them, so we do so unconditionally. // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.if == '\u2028' || == '\u2029' {if < { .Write([:]) } .WriteString(`\u202`) .WriteByte(hex[&0xF]) += = continue } += }if < len() { .Write([:]) } .WriteByte('"')}// A field represents a single field found in a struct.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}// byIndex sorts field by index sequence.type byIndex []fieldfunc ( byIndex) () int { returnlen() }func ( byIndex) (, int) { [], [] = [], [] }func ( byIndex) (, int) bool {for , := range [].index {if >= len([].index) {returnfalse }if != [].index[] {return < [].index[] } }returnlen([].index) < len([].index)}// typeFields returns a list of fields that JSON should recognize for the given type.// The algorithm is breadth-first search over the set of structs to include - the top struct// and then any reachable anonymous structs.func typeFields( reflect.Type) structFields {// Anonymous fields to explore at the current level and the next. := []field{} := []field{{typ: }}// Count of queued names for current level and the next.var , map[reflect.Type]int// Types already visited at an earlier level. := map[reflect.Type]bool{}// Fields found.var []field// Buffer to run HTMLEscape on field names.varbytes.Bufferforlen() > 0 { , = , [:0] , = , map[reflect.Type]int{}for , := range {if [.typ] {continue } [.typ] = true// Scan f.typ for fields to include.for := 0; < .typ.NumField(); ++ { := .typ.Field()if .Anonymous { := .Typeif .Kind() == reflect.Pointer { = .Elem() }if !.IsExported() && .Kind() != reflect.Struct {// Ignore embedded fields of unexported non-struct types.continue }// Do not ignore embedded fields of unexported struct types // since they may have exported fields. } elseif !.IsExported() {// Ignore unexported non-embedded fields.continue } := .Tag.Get("json")if == "-" {continue } , := parseTag()if !isValidTag() { = "" } := make([]int, len(.index)+1)copy(, .index) [len(.index)] = := .Typeif .Name() == "" && .Kind() == reflect.Pointer {// Follow pointer. = .Elem() }// Only strings, floats, integers, and booleans can be quoted. := falseif .Contains("string") {switch .Kind() {casereflect.Bool,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,reflect.String: = true } }// Record found field and index sequence.if != "" || !.Anonymous || .Kind() != reflect.Struct { := != ""if == "" { = .Name } := field{name: ,tag: ,index: ,typ: ,omitEmpty: .Contains("omitempty"),quoted: , } .nameBytes = []byte(.name) .equalFold = foldFunc(.nameBytes)// Build nameEscHTML and nameNonEsc ahead of time. .Reset() .WriteString(`"`)HTMLEscape(&, .nameBytes) .WriteString(`":`) .nameEscHTML = .String() .nameNonEsc = `"` + .name + `":` = append(, )if [.typ] > 1 {// If there were multiple instances, add a second, // so that the annihilation code will see a duplicate. // It only cares about the distinction between 1 or 2, // so don't bother generating any more copies. = append(, [len()-1]) }continue }// Record new anonymous struct to explore in next round. []++if [] == 1 { = append(, field{name: .Name(), index: , typ: }) } } } }sort.Slice(, func(, int) bool { := // sort field by name, breaking ties with depth, then // breaking ties with "name came from json tag", then // breaking ties with index sequence.if [].name != [].name {return [].name < [].name }iflen([].index) != len([].index) {returnlen([].index) < len([].index) }if [].tag != [].tag {return [].tag }returnbyIndex().Less(, ) })// Delete all fields that are hidden by the Go rules for embedded fields, // except that fields with JSON tags are promoted.// The fields are sorted in primary order of name, secondary order // of field index length. Loop over names; for each name, delete // hidden fields by choosing the one dominant field that survives. := [:0]for , := 0, 0; < len(); += {// One iteration per name. // Find the sequence of fields with the name of this first field. := [] := .namefor = 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] = }returnstructFields{, }}// dominantField looks through the fields, all of which are known to// have the same name, to find the single field that dominates the// others using Go's embedding rules, modified by the presence of// JSON tags. If there are multiple top-level fields, the boolean// will be false: This condition is an error in Go and we skip all// the fields.func dominantField( []field) (field, bool) {// The fields are sorted in increasing index-length order, then by presence of tag. // That means that the first field is the dominant one. We need only check // for error cases: two fields at top level, either both tagged or neither tagged.iflen() > 1 && len([0].index) == len([1].index) && [0].tag == [1].tag {returnfield{}, false }return [0], true}var fieldCache sync.Map// map[reflect.Type]structFields// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.func cachedTypeFields( reflect.Type) structFields {if , := fieldCache.Load(); {return .(structFields) } , := fieldCache.LoadOrStore(, typeFields())return .(structFields)}
The pages are generated with Goldsv0.6.4. (GOOS=linux 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.