1package apijson
2
3import (
4 "reflect"
5
6 "github.com/tidwall/gjson"
7)
8
9type UnionVariant struct {
10 TypeFilter gjson.Type
11 DiscriminatorValue any
12 Type reflect.Type
13}
14
15var unionRegistry = map[reflect.Type]unionEntry{}
16var unionVariants = map[reflect.Type]any{}
17
18type unionEntry struct {
19 discriminatorKey string
20 variants []UnionVariant
21}
22
23func Discriminator[T any](value any) UnionVariant {
24 var zero T
25 return UnionVariant{
26 TypeFilter: gjson.JSON,
27 DiscriminatorValue: value,
28 Type: reflect.TypeOf(zero),
29 }
30}
31
32func RegisterUnion[T any](discriminator string, variants ...UnionVariant) {
33 typ := reflect.TypeOf((*T)(nil)).Elem()
34 unionRegistry[typ] = unionEntry{
35 discriminatorKey: discriminator,
36 variants: variants,
37 }
38 for _, variant := range variants {
39 unionVariants[variant.Type] = typ
40 }
41}
42
43// Useful to wrap a union type to force it to use [apijson.UnmarshalJSON] since you cannot define an
44// UnmarshalJSON function on the interface itself.
45type UnionUnmarshaler[T any] struct {
46 Value T
47}
48
49func (c *UnionUnmarshaler[T]) UnmarshalJSON(buf []byte) error {
50 return UnmarshalRoot(buf, &c.Value)
51}