1
2
3
4
5 package unify
6
7 import (
8 "fmt"
9 "reflect"
10 "regexp"
11 "strconv"
12 "strings"
13 "sync"
14 "unicode"
15 )
16
17
18
19
20
21
22
23
24
25
26
27 func (v *Value) Decode(into any) error {
28 rv := reflect.ValueOf(into)
29 if rv.Kind() != reflect.Pointer {
30 return fmt.Errorf("cannot decode into non-pointer %T", into)
31 }
32 return decodeReflect(v, rv.Elem())
33 }
34
35
36
37
38
39
40
41
42
43 func Encode(gv any) *Value {
44 rv := reflect.ValueOf(gv)
45 return encodeReflect(rv)
46 }
47
48
49
50 type DecoderEncoder interface {
51 DecodeUnified(v *Value) error
52 EncodeUnified() *Value
53 }
54
55 var decoderEncoder = reflect.TypeFor[DecoderEncoder]()
56
57 func decodeReflect(v *Value, rv reflect.Value) error {
58 var ptr reflect.Value
59 if rv.Kind() == reflect.Pointer {
60 if rv.IsNil() {
61
62
63
64
65
66 if _, ok := v.Domain.(Top); !ok {
67
68
69 ptr = rv
70 rv = reflect.New(rv.Type().Elem()).Elem()
71 }
72 } else {
73 rv = rv.Elem()
74 }
75 }
76
77 var err error
78 if reflect.PointerTo(rv.Type()).Implements(decoderEncoder) {
79
80 err = rv.Addr().Interface().(DecoderEncoder).DecodeUnified(v)
81 } else {
82 err = v.Domain.decode(rv)
83 }
84 if err == nil && ptr.IsValid() {
85 ptr.Set(rv.Addr())
86 }
87 return err
88 }
89
90 type inexactError struct {
91 valueType string
92 goType string
93 }
94
95 func (e *inexactError) Error() string {
96 return fmt.Sprintf("cannot store inexact %s value in %s", e.valueType, e.goType)
97 }
98
99 type decodeError struct {
100 path string
101 err error
102 }
103
104 func newDecodeError(path string, err error) *decodeError {
105 if err, ok := err.(*decodeError); ok {
106 return &decodeError{path: path + "." + err.path, err: err.err}
107 }
108 return &decodeError{path: path, err: err}
109 }
110
111 func (e *decodeError) Unwrap() error {
112 return e.err
113 }
114
115 func (e *decodeError) Error() string {
116 return fmt.Sprintf("%s: %s", e.path, e.err)
117 }
118
119 func (d Var) decode(rv reflect.Value) error {
120 return &inexactError{"var", rv.Type().String()}
121 }
122
123 func encodeReflect(rv reflect.Value) *Value {
124 if rv.Kind() == reflect.Pointer {
125
126 if rv.IsNil() {
127 return topValue
128 }
129 if re, ok := rv.Interface().(*regexp.Regexp); ok {
130 if exact, complete := re.LiteralPrefix(); complete {
131 return NewValue(NewStringExact(exact))
132 }
133 return NewValue(String{kind: stringRegex, re: []*regexp.Regexp{re}})
134 }
135 rv = rv.Elem()
136 }
137
138 if reflect.PointerTo(rv.Type()).Implements(decoderEncoder) {
139
140 return rv.Addr().Interface().(DecoderEncoder).EncodeUnified()
141 }
142
143 switch rv.Kind() {
144 default:
145 panic(fmt.Sprintf("cannot encode type %s to a unify.Value", rv.Type()))
146
147 case reflect.Struct:
148 var db DefBuilder
149 fieldMap := canonStructFields(rv.Type())
150 for defName, f := range fieldMap {
151 if f.encode.Index == nil {
152 continue
153 }
154 fVal := rv.FieldByIndex(f.encode.Index)
155 if fVal.Kind() == reflect.Pointer && fVal.IsNil() {
156
157
158 continue
159 }
160 uv := encodeReflect(fVal)
161 db.Add(defName, uv)
162 }
163 return NewValue(db.Build())
164
165 case reflect.Slice:
166 uvs := make([]*Value, rv.Len())
167 for i := range rv.Len() {
168 uvs[i] = encodeReflect(rv.Index(i))
169 }
170 return NewValue(NewTuple(uvs...))
171
172 case reflect.String, reflect.Int, reflect.Bool:
173 return NewValue(NewStringExact(fmt.Sprint(rv)))
174 }
175 }
176
177 func (t Top) decode(rv reflect.Value) error {
178
179 if rv.Kind() != reflect.Pointer {
180 return &inexactError{"top", rv.Type().String()}
181 }
182 rv.SetZero()
183 return nil
184 }
185
186 func (d Def) decode(rv reflect.Value) error {
187 if rv.Kind() != reflect.Struct {
188 return fmt.Errorf("cannot decode Def into %s", rv.Type())
189 }
190
191 fieldMap := canonStructFields(rv.Type())
192 for defName, f := range fieldMap {
193 if f.decode.Index == nil {
194 continue
195 }
196 v := d.fields[defName]
197 if v == nil {
198 v = topValue
199 }
200 if err := decodeReflect(v, rv.FieldByIndex(f.decode.Index)); err != nil {
201 return newDecodeError(f.decode.Name, err)
202 }
203 }
204 return nil
205 }
206
207 type structFieldPair struct {
208 decode reflect.StructField
209 encode reflect.StructField
210 }
211
212 var structFieldsCache sync.Map
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 func canonStructFields(rt reflect.Type) map[string]structFieldPair {
238 type fieldMap = map[string]structFieldPair
239 if fields, ok := structFieldsCache.Load(rt); ok {
240 return fields.(fieldMap)
241 }
242
243 fm := make(fieldMap)
244 for f := range rt.Fields() {
245 if !f.IsExported() {
246 continue
247 }
248 if isEncodeOverride(f.Name) {
249 defName := lowerGoName(f.Name[6:])
250 pair := fm[defName]
251 pair.encode = f
252 fm[defName] = pair
253 } else {
254 defName := lowerGoName(f.Name)
255 pair := fm[defName]
256 if pair.decode.Index != nil {
257 panic(fmt.Sprintf("multiple fields in type %s map to %q", rt, defName))
258 }
259 pair.decode = f
260 if pair.encode.Index == nil {
261 pair.encode = f
262 }
263 fm[defName] = pair
264 }
265 }
266
267 res, _ := structFieldsCache.LoadOrStore(rt, fm)
268 return res.(fieldMap)
269 }
270
271 func isEncodeOverride(name string) bool {
272 return strings.HasPrefix(name, "Encode") && len(name) > 6 && unicode.IsUpper(rune(name[6]))
273 }
274
275 func lowerGoName(goName string) string {
276 prefixBytes := -1
277 prevBytes := 0
278 allUpper := true
279 for pos, ch := range goName {
280 if !unicode.IsUpper(ch) {
281 allUpper = false
282 prefixBytes = pos
283 break
284 }
285 prevBytes = pos
286 }
287 if allUpper {
288
289 return strings.ToLower(goName)
290 }
291 if prevBytes == 0 {
292
293 prevBytes = prefixBytes
294 }
295
296 return strings.ToLower(goName[:prevBytes]) + goName[prevBytes:]
297 }
298
299 func (d Tuple) decode(rv reflect.Value) error {
300 if d.repeat != nil {
301 return &inexactError{"repeated tuple", rv.Type().String()}
302 }
303
304 if rv.Kind() != reflect.Slice {
305 return fmt.Errorf("cannot decode Tuple into %s", rv.Type())
306 }
307 if rv.IsNil() || rv.Cap() < len(d.vs) {
308 rv.Set(reflect.MakeSlice(rv.Type(), len(d.vs), len(d.vs)))
309 } else {
310 rv.SetLen(len(d.vs))
311 }
312 for i, v := range d.vs {
313 if err := decodeReflect(v, rv.Index(i)); err != nil {
314 return newDecodeError(fmt.Sprintf("%d", i), err)
315 }
316 }
317 return nil
318 }
319
320 func (d String) decode(rv reflect.Value) error {
321 if d.kind != stringExact {
322 return &inexactError{"regex", rv.Type().String()}
323 }
324 switch rv.Kind() {
325 default:
326 return fmt.Errorf("cannot decode String into %s", rv.Type())
327 case reflect.String:
328 rv.SetString(d.exact)
329 case reflect.Int:
330 i, err := strconv.Atoi(d.exact)
331 if err != nil {
332 return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
333 }
334 rv.SetInt(int64(i))
335 case reflect.Bool:
336 b, err := strconv.ParseBool(d.exact)
337 if err != nil {
338 return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
339 }
340 rv.SetBool(b)
341 }
342 return nil
343 }
344
View as plain text