diff options
Diffstat (limited to 'libgo/go/encoding/json/encode.go')
-rw-r--r-- | libgo/go/encoding/json/encode.go | 55 |
1 files changed, 31 insertions, 24 deletions
diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index dea63f1..464ee3e 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -45,11 +45,12 @@ import ( // // String values encode as JSON strings coerced to valid UTF-8, // replacing invalid bytes with the Unicode replacement rune. -// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" -// to keep some browsers from misinterpreting JSON output as HTML. -// Ampersand "&" is also escaped to "\u0026" for the same reason. -// This escaping can be disabled using an Encoder that had SetEscapeHTML(false) -// called on it. +// 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 @@ -269,6 +270,8 @@ func (e *MarshalerError) Error() string { return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Err.Error() } +func (e *MarshalerError) Unwrap() error { return e.Err } + var hex = "0123456789abcdef" // An encodeState encodes JSON into a bytes.Buffer. @@ -392,19 +395,15 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc { if t.Implements(marshalerType) { return marshalerEncoder } - if t.Kind() != reflect.Ptr && allowAddr { - if reflect.PtrTo(t).Implements(marshalerType) { - return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false)) - } + if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(marshalerType) { + return newCondAddrEncoder(addrMarshalerEncoder, newTypeEncoder(t, false)) } if t.Implements(textMarshalerType) { return textMarshalerEncoder } - if t.Kind() != reflect.Ptr && allowAddr { - if reflect.PtrTo(t).Implements(textMarshalerType) { - return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false)) - } + if t.Kind() != reflect.Ptr && allowAddr && reflect.PtrTo(t).Implements(textMarshalerType) { + return newCondAddrEncoder(addrTextMarshalerEncoder, newTypeEncoder(t, false)) } switch t.Kind() { @@ -625,14 +624,19 @@ func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { } type structEncoder struct { - fields []field + fields structFields +} + +type structFields struct { + list []field + nameIndex map[string]int } func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { next := byte('{') FieldLoop: - for i := range se.fields { - f := &se.fields[i] + for i := range se.fields.list { + f := &se.fields.list[i] // Find the nested struct field by following f.index. fv := v @@ -1067,14 +1071,13 @@ func (x byIndex) Less(i, j int) bool { // 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(t reflect.Type) []field { +func typeFields(t reflect.Type) structFields { // Anonymous fields to explore at the current level and the next. current := []field{} next := []field{{typ: t}} // Count of queued names for current level and the next. - count := map[reflect.Type]int{} - nextCount := map[reflect.Type]int{} + var count, nextCount map[reflect.Type]int // Types already visited at an earlier level. visited := map[reflect.Type]bool{} @@ -1242,7 +1245,11 @@ func typeFields(t reflect.Type) []field { f := &fields[i] f.encoder = typeEncoder(typeByIndex(t, f.index)) } - return fields + nameIndex := make(map[string]int, len(fields)) + for i, field := range fields { + nameIndex[field.name] = i + } + return structFields{fields, nameIndex} } // dominantField looks through the fields, all of which are known to @@ -1261,13 +1268,13 @@ func dominantField(fields []field) (field, bool) { return fields[0], true } -var fieldCache sync.Map // map[reflect.Type][]field +var fieldCache sync.Map // map[reflect.Type]structFields // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. -func cachedTypeFields(t reflect.Type) []field { +func cachedTypeFields(t reflect.Type) structFields { if f, ok := fieldCache.Load(t); ok { - return f.([]field) + return f.(structFields) } f, _ := fieldCache.LoadOrStore(t, typeFields(t)) - return f.([]field) + return f.(structFields) } |