1
2
3
4
5 package unify
6
7 import (
8 "fmt"
9 "iter"
10 "maps"
11 "reflect"
12 "regexp"
13 "slices"
14 "strconv"
15 "strings"
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 type Domain interface {
41 Exact() bool
42 WhyNotExact() string
43
44
45
46 decode(reflect.Value) error
47 }
48
49 type inexactError struct {
50 valueType string
51 goType string
52 }
53
54 func (e *inexactError) Error() string {
55 return fmt.Sprintf("cannot store inexact %s value in %s", e.valueType, e.goType)
56 }
57
58 type decodeError struct {
59 path string
60 err error
61 }
62
63 func newDecodeError(path string, err error) *decodeError {
64 if err, ok := err.(*decodeError); ok {
65 return &decodeError{path: path + "." + err.path, err: err.err}
66 }
67 return &decodeError{path: path, err: err}
68 }
69
70 func (e *decodeError) Unwrap() error {
71 return e.err
72 }
73
74 func (e *decodeError) Error() string {
75 return fmt.Sprintf("%s: %s", e.path, e.err)
76 }
77
78
79 type Top struct{}
80
81 func (t Top) Exact() bool { return false }
82 func (t Top) WhyNotExact() string { return "is top" }
83
84 func (t Top) decode(rv reflect.Value) error {
85
86 if rv.Kind() != reflect.Pointer {
87 return &inexactError{"top", rv.Type().String()}
88 }
89 rv.SetZero()
90 return nil
91 }
92
93
94
95 type Def struct {
96 fields map[string]*Value
97 }
98
99
100
101 type DefBuilder struct {
102 fields map[string]*Value
103 }
104
105 func (b *DefBuilder) Add(name string, v *Value) {
106 if b.fields == nil {
107 b.fields = make(map[string]*Value)
108 }
109 if old, ok := b.fields[name]; ok {
110 panic(fmt.Sprintf("duplicate field %q, added value is %v, old value is %v", name, v, old))
111 }
112 b.fields[name] = v
113 }
114
115
116 func (b *DefBuilder) Build() Def {
117 return Def{maps.Clone(b.fields)}
118 }
119
120
121 func (d Def) Exact() bool {
122 for _, v := range d.fields {
123 if !v.Exact() {
124 return false
125 }
126 }
127 return true
128 }
129
130
131 func (d Def) WhyNotExact() string {
132 for s, v := range d.fields {
133 if !v.Exact() {
134 w := v.WhyNotExact()
135 return "field " + s + ": " + w
136 }
137 }
138 return ""
139 }
140
141 func (d Def) decode(rv reflect.Value) error {
142 if rv.Kind() != reflect.Struct {
143 return fmt.Errorf("cannot decode Def into %s", rv.Type())
144 }
145
146 var lowered map[string]string
147 rt := rv.Type()
148 for fi := range rv.NumField() {
149 fType := rt.Field(fi)
150 if fType.PkgPath != "" {
151 continue
152 }
153 v := d.fields[fType.Name]
154 if v == nil {
155 v = topValue
156
157
158 canon, ok := d.fields[strings.ToLower(fType.Name)]
159 if ok {
160 v = canon
161 } else {
162 if lowered == nil {
163 lowered = make(map[string]string, len(d.fields))
164 for k := range d.fields {
165 l := strings.ToLower(k)
166 if k != l {
167 lowered[l] = k
168 }
169 }
170 }
171 canon, ok := lowered[strings.ToLower(fType.Name)]
172 if ok {
173 v = d.fields[canon]
174 }
175 }
176 }
177 if err := decodeReflect(v, rv.Field(fi)); err != nil {
178 return newDecodeError(fType.Name, err)
179 }
180 }
181 return nil
182 }
183
184 func (d Def) keys() []string {
185 return slices.Sorted(maps.Keys(d.fields))
186 }
187
188 func (d Def) All() iter.Seq2[string, *Value] {
189
190
191 keys := slices.Sorted(maps.Keys(d.fields))
192 return func(yield func(string, *Value) bool) {
193 for _, k := range keys {
194 if !yield(k, d.fields[k]) {
195 return
196 }
197 }
198 }
199 }
200
201
202
203
204 type Tuple struct {
205 vs []*Value
206
207
208
209
210
211
212 repeat []func(envSet) (*Value, envSet)
213 }
214
215 func NewTuple(vs ...*Value) Tuple {
216 return Tuple{vs: vs}
217 }
218
219 func NewRepeat(gens ...func(envSet) (*Value, envSet)) Tuple {
220 return Tuple{repeat: gens}
221 }
222
223 func (d Tuple) Exact() bool {
224 if d.repeat != nil {
225 return false
226 }
227 for _, v := range d.vs {
228 if !v.Exact() {
229 return false
230 }
231 }
232 return true
233 }
234
235 func (d Tuple) WhyNotExact() string {
236 if d.repeat != nil {
237 return "d.repeat is not nil"
238 }
239 for i, v := range d.vs {
240 if !v.Exact() {
241 w := v.WhyNotExact()
242 return "index " + strconv.FormatInt(int64(i), 10) + ": " + w
243 }
244 }
245 return ""
246 }
247
248 func (d Tuple) decode(rv reflect.Value) error {
249 if d.repeat != nil {
250 return &inexactError{"repeated tuple", rv.Type().String()}
251 }
252
253 if rv.Kind() != reflect.Slice {
254 return fmt.Errorf("cannot decode Tuple into %s", rv.Type())
255 }
256 if rv.IsNil() || rv.Cap() < len(d.vs) {
257 rv.Set(reflect.MakeSlice(rv.Type(), len(d.vs), len(d.vs)))
258 } else {
259 rv.SetLen(len(d.vs))
260 }
261 for i, v := range d.vs {
262 if err := decodeReflect(v, rv.Index(i)); err != nil {
263 return newDecodeError(fmt.Sprintf("%d", i), err)
264 }
265 }
266 return nil
267 }
268
269
270
271
272 type String struct {
273 kind stringKind
274 re []*regexp.Regexp
275 exact string
276 }
277
278 type stringKind int
279
280 const (
281 stringRegex stringKind = iota
282 stringExact
283 )
284
285 func NewStringRegex(exprs ...string) (String, error) {
286 if len(exprs) == 0 {
287 exprs = []string{""}
288 }
289 v := String{kind: -1}
290 for _, expr := range exprs {
291 if expr == "" {
292
293
294
295 v = String{kind: stringExact, exact: ""}
296 continue
297 }
298
299 re, err := regexp.Compile(`\A(?:` + expr + `)\z`)
300 if err != nil {
301 return String{}, fmt.Errorf("parsing value: %s", err)
302 }
303
304
305
306 if v.kind == stringExact {
307 continue
308 }
309
310 if exact, complete := re.LiteralPrefix(); complete {
311 v = String{kind: stringExact, exact: exact}
312 } else {
313 v.kind = stringRegex
314 v.re = append(v.re, re)
315 }
316 }
317 return v, nil
318 }
319
320 func NewStringExact(s string) String {
321 return String{kind: stringExact, exact: s}
322 }
323
324
325 func (d String) Exact() bool {
326 return d.kind == stringExact
327 }
328
329 func (d String) WhyNotExact() string {
330 if d.kind == stringExact {
331 return ""
332 }
333 return "string is not exact"
334 }
335
336 func (d String) decode(rv reflect.Value) error {
337 if d.kind != stringExact {
338 return &inexactError{"regex", rv.Type().String()}
339 }
340 switch rv.Kind() {
341 default:
342 return fmt.Errorf("cannot decode String into %s", rv.Type())
343 case reflect.String:
344 rv.SetString(d.exact)
345 case reflect.Int:
346 i, err := strconv.Atoi(d.exact)
347 if err != nil {
348 return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
349 }
350 rv.SetInt(int64(i))
351 case reflect.Bool:
352 b, err := strconv.ParseBool(d.exact)
353 if err != nil {
354 return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
355 }
356 rv.SetBool(b)
357 }
358 return nil
359 }
360
View as plain text