-
Notifications
You must be signed in to change notification settings - Fork 245
/
registration.go
106 lines (87 loc) · 3.5 KB
/
registration.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package types
import (
"fmt"
"github.com/authzed/cel-go/cel"
"github.com/authzed/cel-go/common/types/ref"
"github.com/authzed/spicedb/pkg/genutil"
)
var definitions = map[string]typeDefinition{}
// CustomTypes holds the set of custom types defined and exported by this package. This is exported
// so that the CEL environment construction can apply the necessary env options for the custom
// types.
var CustomTypes = map[string][]cel.EnvOption{}
// CustomMethodsOnTypes holds a set of new methods applied over defined types. This is exported
// so that the CEL environment construction can apply the necessary env options to support these methods
var CustomMethodsOnTypes []cel.EnvOption
type (
typedValueConverter func(value any) (any, error)
)
type typeDefinition struct {
// localName is the localized name/keyword for the type.
localName string
// childTypeCount is the number of generics on the type, if any.
childTypeCount uint8
// asVariableType converts the type definition into a VariableType.
asVariableType func(childTypes []VariableType) (*VariableType, error)
}
// registerBasicType registers a basic type with the given keyword, CEL type, and converter.
func registerBasicType(keyword string, celType *cel.Type, converter typedValueConverter) VariableType {
varType := VariableType{
localName: keyword,
celType: celType,
childTypes: nil,
converter: converter,
}
definitions[keyword] = typeDefinition{
localName: keyword,
childTypeCount: 0,
asVariableType: func(childTypes []VariableType) (*VariableType, error) {
return &varType, nil
},
}
return varType
}
// registerGenericType registers a type with at least one generic.
func registerGenericType(
keyword string,
childTypeCount uint8,
asVariableType func(childTypes []VariableType) VariableType,
) func(childTypes ...VariableType) (VariableType, error) {
definitions[keyword] = typeDefinition{
localName: keyword,
childTypeCount: childTypeCount,
asVariableType: func(childTypes []VariableType) (*VariableType, error) {
childTypeLength, err := genutil.EnsureUInt8(len(childTypes))
if err != nil {
return nil, err
}
if childTypeLength != childTypeCount {
return nil, fmt.Errorf("type `%s` requires %d generic types; found %d", keyword, childTypeCount, len(childTypes))
}
built := asVariableType(childTypes)
return &built, nil
},
}
return func(childTypes ...VariableType) (VariableType, error) {
childTypeLength, err := genutil.EnsureUInt8(len(childTypes))
if err != nil {
return VariableType{}, err
}
if childTypeLength != childTypeCount {
return VariableType{}, fmt.Errorf("invalid number of parameters given to type constructor. expected: %d, found: %d", childTypeCount, len(childTypes))
}
return asVariableType(childTypes), nil
}
}
// registerCustomType registers a custom type that wraps a base CEL type.
func registerCustomType[T CustomType](keyword string, baseCelType *cel.Type, converter typedValueConverter, opts ...cel.EnvOption) VariableType {
CustomTypes[keyword] = opts
return registerBasicType(keyword, baseCelType, converter)
}
func registerMethodOnDefinedType(baseType *cel.Type, name string, args []*cel.Type, returnType *cel.Type, binding func(arg ...ref.Val) ref.Val) {
finalArgs := make([]*cel.Type, 0, len(args)+1)
finalArgs = append(finalArgs, baseType)
finalArgs = append(finalArgs, args...)
method := cel.Function(name, cel.MemberOverload(name, finalArgs, returnType, cel.FunctionBinding(binding)))
CustomMethodsOnTypes = append(CustomMethodsOnTypes, method)
}