You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

254 lines
6.4 KiB

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