1
2
3
4
5 package unify
6
7 import (
8 "fmt"
9 "reflect"
10 "strconv"
11 "strings"
12 "sync"
13 "unicode"
14 )
15
16
17
18
19
20
21
22
23
24
25
26 func (v *Value) Decode(into any) error {
27 rv := reflect.ValueOf(into)
28 if rv.Kind() != reflect.Pointer {
29 return fmt.Errorf("cannot decode into non-pointer %T", into)
30 }
31 return decodeReflect(v, rv.Elem())
32 }
33
34
35
36 type Decoder interface {
37 DecodeUnified(v *Value) error
38 }
39
40 var decoderType = reflect.TypeFor[Decoder]()
41
42 func decodeReflect(v *Value, rv reflect.Value) error {
43 var ptr reflect.Value
44 if rv.Kind() == reflect.Pointer {
45 if rv.IsNil() {
46
47
48
49
50
51 if _, ok := v.Domain.(Top); !ok {
52
53
54 ptr = rv
55 rv = reflect.New(rv.Type().Elem()).Elem()
56 }
57 } else {
58 rv = rv.Elem()
59 }
60 }
61
62 var err error
63 if reflect.PointerTo(rv.Type()).Implements(decoderType) {
64
65 err = rv.Addr().Interface().(Decoder).DecodeUnified(v)
66 } else {
67 err = v.Domain.decode(rv)
68 }
69 if err == nil && ptr.IsValid() {
70 ptr.Set(rv.Addr())
71 }
72 return err
73 }
74
75 type inexactError struct {
76 valueType string
77 goType string
78 }
79
80 func (e *inexactError) Error() string {
81 return fmt.Sprintf("cannot store inexact %s value in %s", e.valueType, e.goType)
82 }
83
84 type decodeError struct {
85 path string
86 err error
87 }
88
89 func newDecodeError(path string, err error) *decodeError {
90 if err, ok := err.(*decodeError); ok {
91 return &decodeError{path: path + "." + err.path, err: err.err}
92 }
93 return &decodeError{path: path, err: err}
94 }
95
96 func (e *decodeError) Unwrap() error {
97 return e.err
98 }
99
100 func (e *decodeError) Error() string {
101 return fmt.Sprintf("%s: %s", e.path, e.err)
102 }
103
104 func (d Var) decode(rv reflect.Value) error {
105 return &inexactError{"var", rv.Type().String()}
106 }
107
108 func (t Top) decode(rv reflect.Value) error {
109
110 if rv.Kind() != reflect.Pointer {
111 return &inexactError{"top", rv.Type().String()}
112 }
113 rv.SetZero()
114 return nil
115 }
116
117 func (d Def) decode(rv reflect.Value) error {
118 if rv.Kind() != reflect.Struct {
119 return fmt.Errorf("cannot decode Def into %s", rv.Type())
120 }
121
122 fieldMap := canonStructFields(rv.Type())
123 for defName, f := range fieldMap {
124 v := d.fields[defName]
125 if v == nil {
126 v = topValue
127 }
128 if err := decodeReflect(v, rv.FieldByIndex(f.Index)); err != nil {
129 return newDecodeError(f.Name, err)
130 }
131 }
132 return nil
133 }
134
135 var structFieldsCache sync.Map
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 func canonStructFields(rt reflect.Type) map[string]reflect.StructField {
155 type fieldMap = map[string]reflect.StructField
156 if fields, ok := structFieldsCache.Load(rt); ok {
157 return fields.(fieldMap)
158 }
159
160 fm := make(fieldMap)
161 for f := range rt.Fields() {
162 if !f.IsExported() {
163 continue
164 }
165 defName := lowerGoName(f.Name)
166 if _, ok := fm[defName]; ok {
167 panic(fmt.Sprintf("multiple fields in type %s map to %q", rt, defName))
168 }
169 fm[defName] = f
170 }
171
172 res, _ := structFieldsCache.LoadOrStore(rt, fm)
173 return res.(fieldMap)
174 }
175
176 func lowerGoName(goName string) string {
177 prefixBytes := -1
178 prevBytes := 0
179 allUpper := true
180 for pos, ch := range goName {
181 if !unicode.IsUpper(ch) {
182 allUpper = false
183 prefixBytes = pos
184 break
185 }
186 prevBytes = pos
187 }
188 if allUpper {
189
190 return strings.ToLower(goName)
191 }
192 if prevBytes == 0 {
193
194 prevBytes = prefixBytes
195 }
196
197 return strings.ToLower(goName[:prevBytes]) + goName[prevBytes:]
198 }
199
200 func (d Tuple) decode(rv reflect.Value) error {
201 if d.repeat != nil {
202 return &inexactError{"repeated tuple", rv.Type().String()}
203 }
204
205 if rv.Kind() != reflect.Slice {
206 return fmt.Errorf("cannot decode Tuple into %s", rv.Type())
207 }
208 if rv.IsNil() || rv.Cap() < len(d.vs) {
209 rv.Set(reflect.MakeSlice(rv.Type(), len(d.vs), len(d.vs)))
210 } else {
211 rv.SetLen(len(d.vs))
212 }
213 for i, v := range d.vs {
214 if err := decodeReflect(v, rv.Index(i)); err != nil {
215 return newDecodeError(fmt.Sprintf("%d", i), err)
216 }
217 }
218 return nil
219 }
220
221 func (d String) decode(rv reflect.Value) error {
222 if d.kind != stringExact {
223 return &inexactError{"regex", rv.Type().String()}
224 }
225 switch rv.Kind() {
226 default:
227 return fmt.Errorf("cannot decode String into %s", rv.Type())
228 case reflect.String:
229 rv.SetString(d.exact)
230 case reflect.Int:
231 i, err := strconv.Atoi(d.exact)
232 if err != nil {
233 return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
234 }
235 rv.SetInt(int64(i))
236 case reflect.Bool:
237 b, err := strconv.ParseBool(d.exact)
238 if err != nil {
239 return fmt.Errorf("cannot decode String into %s: %s", rv.Type(), err)
240 }
241 rv.SetBool(b)
242 }
243 return nil
244 }
245
View as plain text