github.com/pure-x-eth/consensus_tm@v0.0.0-20230502163723-e3c2ff987250/libs/json/encoder.go (about) 1 package json 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io" 9 "reflect" 10 "strconv" 11 "time" 12 ) 13 14 var ( 15 timeType = reflect.TypeOf(time.Time{}) 16 jsonMarshalerType = reflect.TypeOf(new(json.Marshaler)).Elem() 17 jsonUnmarshalerType = reflect.TypeOf(new(json.Unmarshaler)).Elem() 18 ) 19 20 // Marshal marshals the value as JSON, using Amino-compatible JSON encoding (strings for 21 // 64-bit numbers, and type wrappers for registered types). 22 func Marshal(v interface{}) ([]byte, error) { 23 buf := new(bytes.Buffer) 24 err := encode(buf, v) 25 if err != nil { 26 return nil, err 27 } 28 return buf.Bytes(), nil 29 } 30 31 // MarshalIndent marshals the value as JSON, using the given prefix and indentation. 32 func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { 33 bz, err := Marshal(v) 34 if err != nil { 35 return nil, err 36 } 37 buf := new(bytes.Buffer) 38 err = json.Indent(buf, bz, prefix, indent) 39 if err != nil { 40 return nil, err 41 } 42 return buf.Bytes(), nil 43 } 44 45 func encode(w io.Writer, v interface{}) error { 46 // Bare nil values can't be reflected, so we must handle them here. 47 if v == nil { 48 return writeStr(w, "null") 49 } 50 rv := reflect.ValueOf(v) 51 52 // If this is a registered type, defer to interface encoder regardless of whether the input is 53 // an interface or a bare value. This retains Amino's behavior, but is inconsistent with 54 // behavior in structs where an interface field will get the type wrapper while a bare value 55 // field will not. 56 if typeRegistry.name(rv.Type()) != "" { 57 return encodeReflectInterface(w, rv) 58 } 59 60 return encodeReflect(w, rv) 61 } 62 63 func encodeReflect(w io.Writer, rv reflect.Value) error { 64 if !rv.IsValid() { 65 return errors.New("invalid reflect value") 66 } 67 68 // Recursively dereference if pointer. 69 for rv.Kind() == reflect.Ptr { 70 if rv.IsNil() { 71 return writeStr(w, "null") 72 } 73 rv = rv.Elem() 74 } 75 76 // Convert times to UTC. 77 if rv.Type() == timeType { 78 rv = reflect.ValueOf(rv.Interface().(time.Time).Round(0).UTC()) 79 } 80 81 // If the value implements json.Marshaler, defer to stdlib directly. Since we've already 82 // dereferenced, we try implementations with both value receiver and pointer receiver. We must 83 // do this after the time normalization above, and thus after dereferencing. 84 if rv.Type().Implements(jsonMarshalerType) { 85 return encodeStdlib(w, rv.Interface()) 86 } else if rv.CanAddr() && rv.Addr().Type().Implements(jsonMarshalerType) { 87 return encodeStdlib(w, rv.Addr().Interface()) 88 } 89 90 switch rv.Type().Kind() { 91 // Complex types must be recursively encoded. 92 case reflect.Interface: 93 return encodeReflectInterface(w, rv) 94 95 case reflect.Array, reflect.Slice: 96 return encodeReflectList(w, rv) 97 98 case reflect.Map: 99 return encodeReflectMap(w, rv) 100 101 case reflect.Struct: 102 return encodeReflectStruct(w, rv) 103 104 // 64-bit integers are emitted as strings, to avoid precision problems with e.g. 105 // Javascript which uses 64-bit floats (having 53-bit precision). 106 case reflect.Int64, reflect.Int: 107 return writeStr(w, `"`+strconv.FormatInt(rv.Int(), 10)+`"`) 108 109 case reflect.Uint64, reflect.Uint: 110 return writeStr(w, `"`+strconv.FormatUint(rv.Uint(), 10)+`"`) 111 112 // For everything else, defer to the stdlib encoding/json encoder 113 default: 114 return encodeStdlib(w, rv.Interface()) 115 } 116 } 117 118 func encodeReflectList(w io.Writer, rv reflect.Value) error { 119 // Emit nil slices as null. 120 if rv.Kind() == reflect.Slice && rv.IsNil() { 121 return writeStr(w, "null") 122 } 123 124 // Encode byte slices as base64 with the stdlib encoder. 125 if rv.Type().Elem().Kind() == reflect.Uint8 { 126 // Stdlib does not base64-encode byte arrays, only slices, so we copy to slice. 127 if rv.Type().Kind() == reflect.Array { 128 slice := reflect.MakeSlice(reflect.SliceOf(rv.Type().Elem()), rv.Len(), rv.Len()) 129 reflect.Copy(slice, rv) 130 rv = slice 131 } 132 return encodeStdlib(w, rv.Interface()) 133 } 134 135 // Anything else we recursively encode ourselves. 136 length := rv.Len() 137 if err := writeStr(w, "["); err != nil { 138 return err 139 } 140 for i := 0; i < length; i++ { 141 if err := encodeReflect(w, rv.Index(i)); err != nil { 142 return err 143 } 144 if i < length-1 { 145 if err := writeStr(w, ","); err != nil { 146 return err 147 } 148 } 149 } 150 return writeStr(w, "]") 151 } 152 153 func encodeReflectMap(w io.Writer, rv reflect.Value) error { 154 if rv.Type().Key().Kind() != reflect.String { 155 return errors.New("map key must be string") 156 } 157 158 // nil maps are not emitted as nil, to retain Amino compatibility. 159 160 if err := writeStr(w, "{"); err != nil { 161 return err 162 } 163 writeComma := false 164 for _, keyrv := range rv.MapKeys() { 165 if writeComma { 166 if err := writeStr(w, ","); err != nil { 167 return err 168 } 169 } 170 if err := encodeStdlib(w, keyrv.Interface()); err != nil { 171 return err 172 } 173 if err := writeStr(w, ":"); err != nil { 174 return err 175 } 176 if err := encodeReflect(w, rv.MapIndex(keyrv)); err != nil { 177 return err 178 } 179 writeComma = true 180 } 181 return writeStr(w, "}") 182 } 183 184 func encodeReflectStruct(w io.Writer, rv reflect.Value) error { 185 sInfo := makeStructInfo(rv.Type()) 186 if err := writeStr(w, "{"); err != nil { 187 return err 188 } 189 writeComma := false 190 for i, fInfo := range sInfo.fields { 191 frv := rv.Field(i) 192 if fInfo.hidden || (fInfo.omitEmpty && frv.IsZero()) { 193 continue 194 } 195 196 if writeComma { 197 if err := writeStr(w, ","); err != nil { 198 return err 199 } 200 } 201 if err := encodeStdlib(w, fInfo.jsonName); err != nil { 202 return err 203 } 204 if err := writeStr(w, ":"); err != nil { 205 return err 206 } 207 if err := encodeReflect(w, frv); err != nil { 208 return err 209 } 210 writeComma = true 211 } 212 return writeStr(w, "}") 213 } 214 215 func encodeReflectInterface(w io.Writer, rv reflect.Value) error { 216 // Get concrete value and dereference pointers. 217 for rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface { 218 if rv.IsNil() { 219 return writeStr(w, "null") 220 } 221 rv = rv.Elem() 222 } 223 224 // Look up the name of the concrete type 225 name := typeRegistry.name(rv.Type()) 226 if name == "" { 227 return fmt.Errorf("cannot encode unregistered type %v", rv.Type()) 228 } 229 230 // Write value wrapped in interface envelope 231 if err := writeStr(w, fmt.Sprintf(`{"type":%q,"value":`, name)); err != nil { 232 return err 233 } 234 if err := encodeReflect(w, rv); err != nil { 235 return err 236 } 237 return writeStr(w, "}") 238 } 239 240 func encodeStdlib(w io.Writer, v interface{}) error { 241 // Doesn't stream the output because that adds a newline, as per: 242 // https://golang.org/pkg/encoding/json/#Encoder.Encode 243 blob, err := json.Marshal(v) 244 if err != nil { 245 return err 246 } 247 _, err = w.Write(blob) 248 return err 249 } 250 251 func writeStr(w io.Writer, s string) error { 252 _, err := w.Write([]byte(s)) 253 return err 254 }