extension.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package json
  2. import (
  3. "reflect"
  4. )
  5. // Extension holds a set of additional rules to be used when unmarshaling
  6. // strict JSON or JSON-like content.
  7. type Extension struct {
  8. funcs map[string]funcExt
  9. consts map[string]interface{}
  10. keyed map[string]func([]byte) (interface{}, error)
  11. encode map[reflect.Type]func(v interface{}) ([]byte, error)
  12. unquotedKeys bool
  13. trailingCommas bool
  14. }
  15. type funcExt struct {
  16. key string
  17. args []string
  18. }
  19. // Extend changes the decoder behavior to consider the provided extension.
  20. func (dec *Decoder) Extend(ext *Extension) { dec.d.ext = *ext }
  21. // Extend changes the encoder behavior to consider the provided extension.
  22. func (enc *Encoder) Extend(ext *Extension) { enc.ext = *ext }
  23. // Extend includes in e the extensions defined in ext.
  24. func (e *Extension) Extend(ext *Extension) {
  25. for name, fext := range ext.funcs {
  26. e.DecodeFunc(name, fext.key, fext.args...)
  27. }
  28. for name, value := range ext.consts {
  29. e.DecodeConst(name, value)
  30. }
  31. for key, decode := range ext.keyed {
  32. e.DecodeKeyed(key, decode)
  33. }
  34. for typ, encode := range ext.encode {
  35. if e.encode == nil {
  36. e.encode = make(map[reflect.Type]func(v interface{}) ([]byte, error))
  37. }
  38. e.encode[typ] = encode
  39. }
  40. }
  41. // DecodeFunc defines a function call that may be observed inside JSON content.
  42. // A function with the provided name will be unmarshaled as the document
  43. // {key: {args[0]: ..., args[N]: ...}}.
  44. func (e *Extension) DecodeFunc(name string, key string, args ...string) {
  45. if e.funcs == nil {
  46. e.funcs = make(map[string]funcExt)
  47. }
  48. e.funcs[name] = funcExt{key, args}
  49. }
  50. // DecodeConst defines a constant name that may be observed inside JSON content
  51. // and will be decoded with the provided value.
  52. func (e *Extension) DecodeConst(name string, value interface{}) {
  53. if e.consts == nil {
  54. e.consts = make(map[string]interface{})
  55. }
  56. e.consts[name] = value
  57. }
  58. // DecodeKeyed defines a key that when observed as the first element inside a
  59. // JSON document triggers the decoding of that document via the provided
  60. // decode function.
  61. func (e *Extension) DecodeKeyed(key string, decode func(data []byte) (interface{}, error)) {
  62. if e.keyed == nil {
  63. e.keyed = make(map[string]func([]byte) (interface{}, error))
  64. }
  65. e.keyed[key] = decode
  66. }
  67. // DecodeUnquotedKeys defines whether to accept map keys that are unquoted strings.
  68. func (e *Extension) DecodeUnquotedKeys(accept bool) {
  69. e.unquotedKeys = accept
  70. }
  71. // DecodeTrailingCommas defines whether to accept trailing commas in maps and arrays.
  72. func (e *Extension) DecodeTrailingCommas(accept bool) {
  73. e.trailingCommas = accept
  74. }
  75. // EncodeType registers a function to encode values with the same type of the
  76. // provided sample.
  77. func (e *Extension) EncodeType(sample interface{}, encode func(v interface{}) ([]byte, error)) {
  78. if e.encode == nil {
  79. e.encode = make(map[reflect.Type]func(v interface{}) ([]byte, error))
  80. }
  81. e.encode[reflect.TypeOf(sample)] = encode
  82. }