1
2
3
4
5
6
7 package yaml
8
9 import (
10 "errors"
11 "fmt"
12 "io"
13 "reflect"
14 "strings"
15 "sync"
16 )
17
18
19
20 type MapSlice []MapItem
21
22
23 type MapItem struct {
24 Key, Value interface{}
25 }
26
27
28
29
30
31
32 type Unmarshaler interface {
33 UnmarshalYAML(unmarshal func(interface{}) error) error
34 }
35
36
37
38
39
40
41
42 type Marshaler interface {
43 MarshalYAML() (interface{}, error)
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 func Unmarshal(in []byte, out interface{}) (err error) {
81 return unmarshal(in, out, false)
82 }
83
84
85
86
87
88 func UnmarshalStrict(in []byte, out interface{}) (err error) {
89 return unmarshal(in, out, true)
90 }
91
92
93 type Decoder struct {
94 strict bool
95 parser *parser
96 }
97
98
99
100
101
102 func NewDecoder(r io.Reader) *Decoder {
103 return &Decoder{
104 parser: newParserFromReader(r),
105 }
106 }
107
108
109
110 func (dec *Decoder) SetStrict(strict bool) {
111 dec.strict = strict
112 }
113
114
115
116
117
118
119 func (dec *Decoder) Decode(v interface{}) (err error) {
120 d := newDecoder(dec.strict)
121 defer handleErr(&err)
122 node := dec.parser.parse()
123 if node == nil {
124 return io.EOF
125 }
126 out := reflect.ValueOf(v)
127 if out.Kind() == reflect.Ptr && !out.IsNil() {
128 out = out.Elem()
129 }
130 d.unmarshal(node, out)
131 if len(d.terrors) > 0 {
132 return &TypeError{d.terrors}
133 }
134 return nil
135 }
136
137 func unmarshal(in []byte, out interface{}, strict bool) (err error) {
138 defer handleErr(&err)
139 d := newDecoder(strict)
140 p := newParser(in)
141 defer p.destroy()
142 node := p.parse()
143 if node != nil {
144 v := reflect.ValueOf(out)
145 if v.Kind() == reflect.Ptr && !v.IsNil() {
146 v = v.Elem()
147 }
148 d.unmarshal(node, v)
149 }
150 if len(d.terrors) > 0 {
151 return &TypeError{d.terrors}
152 }
153 return nil
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 func Marshal(in interface{}) (out []byte, err error) {
200 defer handleErr(&err)
201 e := newEncoder()
202 defer e.destroy()
203 e.marshalDoc("", reflect.ValueOf(in))
204 e.finish()
205 out = e.out
206 return
207 }
208
209
210 type Encoder struct {
211 encoder *encoder
212 }
213
214
215
216
217 func NewEncoder(w io.Writer) *Encoder {
218 return &Encoder{
219 encoder: newEncoderWithWriter(w),
220 }
221 }
222
223
224
225
226
227
228
229
230 func (e *Encoder) Encode(v interface{}) (err error) {
231 defer handleErr(&err)
232 e.encoder.marshalDoc("", reflect.ValueOf(v))
233 return nil
234 }
235
236
237
238 func (e *Encoder) Close() (err error) {
239 defer handleErr(&err)
240 e.encoder.finish()
241 return nil
242 }
243
244 func handleErr(err *error) {
245 if v := recover(); v != nil {
246 if e, ok := v.(yamlError); ok {
247 *err = e.err
248 } else {
249 panic(v)
250 }
251 }
252 }
253
254 type yamlError struct {
255 err error
256 }
257
258 func fail(err error) {
259 panic(yamlError{err})
260 }
261
262 func failf(format string, args ...interface{}) {
263 panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
264 }
265
266
267
268
269
270 type TypeError struct {
271 Errors []string
272 }
273
274 func (e *TypeError) Error() string {
275 return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
276 }
277
278
279
280
281
282
283
284
285 type structInfo struct {
286 FieldsMap map[string]fieldInfo
287 FieldsList []fieldInfo
288
289
290
291 InlineMap int
292 }
293
294 type fieldInfo struct {
295 Key string
296 Num int
297 OmitEmpty bool
298 Flow bool
299
300
301 Id int
302
303
304 Inline []int
305 }
306
307 var structMap = make(map[reflect.Type]*structInfo)
308 var fieldMapMutex sync.RWMutex
309
310 func getStructInfo(st reflect.Type) (*structInfo, error) {
311 fieldMapMutex.RLock()
312 sinfo, found := structMap[st]
313 fieldMapMutex.RUnlock()
314 if found {
315 return sinfo, nil
316 }
317
318 n := st.NumField()
319 fieldsMap := make(map[string]fieldInfo)
320 fieldsList := make([]fieldInfo, 0, n)
321 inlineMap := -1
322 for i := 0; i != n; i++ {
323 field := st.Field(i)
324 if field.PkgPath != "" && !field.Anonymous {
325 continue
326 }
327
328 info := fieldInfo{Num: i}
329
330 tag := field.Tag.Get("yaml")
331 if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
332 tag = string(field.Tag)
333 }
334 if tag == "-" {
335 continue
336 }
337
338 inline := false
339 fields := strings.Split(tag, ",")
340 if len(fields) > 1 {
341 for _, flag := range fields[1:] {
342 switch flag {
343 case "omitempty":
344 info.OmitEmpty = true
345 case "flow":
346 info.Flow = true
347 case "inline":
348 inline = true
349 default:
350 return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
351 }
352 }
353 tag = fields[0]
354 }
355
356 if inline {
357 switch field.Type.Kind() {
358 case reflect.Map:
359 if inlineMap >= 0 {
360 return nil, errors.New("Multiple ,inline maps in struct " + st.String())
361 }
362 if field.Type.Key() != reflect.TypeOf("") {
363 return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
364 }
365 inlineMap = info.Num
366 case reflect.Struct:
367 sinfo, err := getStructInfo(field.Type)
368 if err != nil {
369 return nil, err
370 }
371 for _, finfo := range sinfo.FieldsList {
372 if _, found := fieldsMap[finfo.Key]; found {
373 msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
374 return nil, errors.New(msg)
375 }
376 if finfo.Inline == nil {
377 finfo.Inline = []int{i, finfo.Num}
378 } else {
379 finfo.Inline = append([]int{i}, finfo.Inline...)
380 }
381 finfo.Id = len(fieldsList)
382 fieldsMap[finfo.Key] = finfo
383 fieldsList = append(fieldsList, finfo)
384 }
385 default:
386
387 return nil, errors.New("Option ,inline needs a struct value field")
388 }
389 continue
390 }
391
392 if tag != "" {
393 info.Key = tag
394 } else {
395 info.Key = strings.ToLower(field.Name)
396 }
397
398 if _, found = fieldsMap[info.Key]; found {
399 msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
400 return nil, errors.New(msg)
401 }
402
403 info.Id = len(fieldsList)
404 fieldsList = append(fieldsList, info)
405 fieldsMap[info.Key] = info
406 }
407
408 sinfo = &structInfo{
409 FieldsMap: fieldsMap,
410 FieldsList: fieldsList,
411 InlineMap: inlineMap,
412 }
413
414 fieldMapMutex.Lock()
415 structMap[st] = sinfo
416 fieldMapMutex.Unlock()
417 return sinfo, nil
418 }
419
420
421
422
423
424 type IsZeroer interface {
425 IsZero() bool
426 }
427
428 func isZero(v reflect.Value) bool {
429 kind := v.Kind()
430 if z, ok := v.Interface().(IsZeroer); ok {
431 if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
432 return true
433 }
434 return z.IsZero()
435 }
436 switch kind {
437 case reflect.String:
438 return len(v.String()) == 0
439 case reflect.Interface, reflect.Ptr:
440 return v.IsNil()
441 case reflect.Slice:
442 return v.Len() == 0
443 case reflect.Map:
444 return v.Len() == 0
445 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
446 return v.Int() == 0
447 case reflect.Float32, reflect.Float64:
448 return v.Float() == 0
449 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
450 return v.Uint() == 0
451 case reflect.Bool:
452 return !v.Bool()
453 case reflect.Struct:
454 vt := v.Type()
455 for i := v.NumField() - 1; i >= 0; i-- {
456 if vt.Field(i).PkgPath != "" {
457 continue
458 }
459 if !isZero(v.Field(i)) {
460 return false
461 }
462 }
463 return true
464 }
465 return false
466 }
467
468
469
470
471
472
473
474
475
476 func FutureLineWrap() {
477 disableLineWrapping = true
478 }
479
View as plain text