json.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package jsonx contains helper types and functionality to use with
  4. // [github.com/go-json-experiment/json], which is positioned to be
  5. // merged into the Go standard library as [encoding/json/v2].
  6. //
  7. // See https://go.dev/issues/71497
  8. package jsonx
  9. import (
  10. "errors"
  11. "fmt"
  12. "reflect"
  13. "github.com/go-json-experiment/json"
  14. "github.com/go-json-experiment/json/jsontext"
  15. )
  16. var (
  17. errUnknownTypeName = errors.New("unknown type name")
  18. errNonSingularValue = errors.New("dynamic value must only have exactly one member")
  19. )
  20. // MakeInterfaceCoders constructs a pair of marshal and unmarshal functions
  21. // to serialize a Go interface type T. A bijective mapping for the set
  22. // of concrete types that implement T is provided,
  23. // where the key is a stable type name to use in the JSON representation,
  24. // while the value is any value of a concrete type that implements T.
  25. // By convention, only the zero value of concrete types is passed.
  26. //
  27. // The JSON representation for a dynamic value is a JSON object
  28. // with a single member, where the member name is the type name,
  29. // and the value is the JSON representation for the Go value.
  30. // For example, the JSON serialization for a concrete type named Foo
  31. // would be {"Foo": ...}, where ... is the JSON representation
  32. // of the concrete value of the Foo type.
  33. //
  34. // Example instantiation:
  35. //
  36. // // Interface is a union type implemented by [FooType] and [BarType].
  37. // type Interface interface { ... }
  38. //
  39. // var interfaceCoders = MakeInterfaceCoders(map[string]Interface{
  40. // "FooType": FooType{},
  41. // "BarType": (*BarType)(nil),
  42. // })
  43. //
  44. // The pair of Marshal and Unmarshal functions can be used with the [json]
  45. // package with either type-specified or caller-specified serialization.
  46. // The result of this constructor is usually stored into a global variable.
  47. //
  48. // Example usage with type-specified serialization:
  49. //
  50. // // InterfaceWrapper is a concrete type that wraps [Interface].
  51. // // It extends [Interface] to implement
  52. // // [json.MarshalerTo] and [json.UnmarshalerFrom].
  53. // type InterfaceWrapper struct{ Interface }
  54. //
  55. // func (w InterfaceWrapper) MarshalJSONTo(enc *jsontext.Encoder) error {
  56. // return interfaceCoders.Marshal(enc, &w.Interface)
  57. // }
  58. //
  59. // func (w *InterfaceWrapper) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
  60. // return interfaceCoders.Unmarshal(dec, &w.Interface)
  61. // }
  62. //
  63. // Example usage with caller-specified serialization:
  64. //
  65. // var opts json.Options = json.JoinOptions(
  66. // json.WithMarshalers(json.MarshalToFunc(interfaceCoders.Marshal)),
  67. // json.WithUnmarshalers(json.UnmarshalFromFunc(interfaceCoders.Unmarshal)),
  68. // )
  69. //
  70. // var v Interface
  71. // ... := json.Marshal(v, opts)
  72. // ... := json.Unmarshal(&v, opts)
  73. //
  74. // The function panics if T is not a named interface kind,
  75. // or if valuesByName contains distinct entries with the same concrete type.
  76. func MakeInterfaceCoders[T any](valuesByName map[string]T) (c struct {
  77. Marshal func(*jsontext.Encoder, *T) error
  78. Unmarshal func(*jsontext.Decoder, *T) error
  79. }) {
  80. // Verify that T is a named interface.
  81. switch t := reflect.TypeFor[T](); {
  82. case t.Kind() != reflect.Interface:
  83. panic(fmt.Sprintf("%v must be an interface kind", t))
  84. case t.Name() == "":
  85. panic(fmt.Sprintf("%v must be a named type", t))
  86. }
  87. // Construct a bijective mapping of names to types.
  88. typesByName := make(map[string]reflect.Type)
  89. namesByType := make(map[reflect.Type]string)
  90. for name, value := range valuesByName {
  91. t := reflect.TypeOf(value)
  92. if t == nil {
  93. panic(fmt.Sprintf("nil value for %s", name))
  94. }
  95. if name2, ok := namesByType[t]; ok {
  96. panic(fmt.Sprintf("type %v cannot have multiple names %s and %v", t, name, name2))
  97. }
  98. typesByName[name] = t
  99. namesByType[t] = name
  100. }
  101. // Construct the marshal and unmarshal functions.
  102. c.Marshal = func(enc *jsontext.Encoder, val *T) error {
  103. t := reflect.TypeOf(*val)
  104. if t == nil {
  105. return enc.WriteToken(jsontext.Null)
  106. }
  107. name := namesByType[t]
  108. if name == "" {
  109. return fmt.Errorf("Go type %v: %w", t, errUnknownTypeName)
  110. }
  111. if err := enc.WriteToken(jsontext.BeginObject); err != nil {
  112. return err
  113. }
  114. if err := enc.WriteToken(jsontext.String(name)); err != nil {
  115. return err
  116. }
  117. if err := json.MarshalEncode(enc, *val); err != nil {
  118. return err
  119. }
  120. if err := enc.WriteToken(jsontext.EndObject); err != nil {
  121. return err
  122. }
  123. return nil
  124. }
  125. c.Unmarshal = func(dec *jsontext.Decoder, val *T) error {
  126. switch tok, err := dec.ReadToken(); {
  127. case err != nil:
  128. return err
  129. case tok.Kind() == 'n':
  130. var zero T
  131. *val = zero // store nil interface value for JSON null
  132. return nil
  133. case tok.Kind() != '{':
  134. return &json.SemanticError{JSONKind: tok.Kind(), GoType: reflect.TypeFor[T]()}
  135. }
  136. var v reflect.Value
  137. switch tok, err := dec.ReadToken(); {
  138. case err != nil:
  139. return err
  140. case tok.Kind() != '"':
  141. return errNonSingularValue
  142. default:
  143. t := typesByName[tok.String()]
  144. if t == nil {
  145. return errUnknownTypeName
  146. }
  147. v = reflect.New(t)
  148. }
  149. if err := json.UnmarshalDecode(dec, v.Interface()); err != nil {
  150. return err
  151. }
  152. *val = v.Elem().Interface().(T)
  153. switch tok, err := dec.ReadToken(); {
  154. case err != nil:
  155. return err
  156. case tok.Kind() != '}':
  157. return errNonSingularValue
  158. }
  159. return nil
  160. }
  161. return c
  162. }