union.go

 1package param
 2
 3import (
 4	"fmt"
 5	"reflect"
 6)
 7
 8var paramUnionType = reflect.TypeOf(APIUnion{})
 9
10// VariantFromUnion can be used to extract the present variant from a param union type.
11// A param union type is a struct with an embedded field of [APIUnion].
12func VariantFromUnion(u reflect.Value) (any, error) {
13	if u.Kind() == reflect.Ptr {
14		u = u.Elem()
15	}
16
17	if u.Kind() != reflect.Struct {
18		return nil, fmt.Errorf("param: cannot extract variant from non-struct union")
19	}
20
21	isUnion := false
22	nVariants := 0
23	variantIdx := -1
24	for i := 0; i < u.NumField(); i++ {
25		if !u.Field(i).IsZero() {
26			nVariants++
27			variantIdx = i
28		}
29		if u.Field(i).Type() == paramUnionType {
30			isUnion = u.Type().Field(i).Anonymous
31		}
32	}
33
34	if !isUnion {
35		return nil, fmt.Errorf("param: cannot extract variant from non-union")
36	}
37
38	if nVariants > 1 {
39		return nil, fmt.Errorf("param: cannot extract variant from union with multiple variants")
40	}
41
42	if nVariants == 0 {
43		return nil, fmt.Errorf("param: cannot extract variant from union with no variants")
44	}
45
46	return u.Field(variantIdx).Interface(), nil
47}