aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/encoding/json/encode.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/encoding/json/encode.go')
-rw-r--r--libgo/go/encoding/json/encode.go55
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)
}