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}