initial commit
[govpp.git] / vendor / gopkg.in / yaml.v2 / yaml.go
1 // Package yaml implements YAML support for the Go language.
2 //
3 // Source code and other details for the project are available at GitHub:
4 //
5 //   https://github.com/go-yaml/yaml
6 //
7 package yaml
8
9 import (
10         "errors"
11         "fmt"
12         "reflect"
13         "strings"
14         "sync"
15 )
16
17 // MapSlice encodes and decodes as a YAML map.
18 // The order of keys is preserved when encoding and decoding.
19 type MapSlice []MapItem
20
21 // MapItem is an item in a MapSlice.
22 type MapItem struct {
23         Key, Value interface{}
24 }
25
26 // The Unmarshaler interface may be implemented by types to customize their
27 // behavior when being unmarshaled from a YAML document. The UnmarshalYAML
28 // method receives a function that may be called to unmarshal the original
29 // YAML value into a field or variable. It is safe to call the unmarshal
30 // function parameter more than once if necessary.
31 type Unmarshaler interface {
32         UnmarshalYAML(unmarshal func(interface{}) error) error
33 }
34
35 // The Marshaler interface may be implemented by types to customize their
36 // behavior when being marshaled into a YAML document. The returned value
37 // is marshaled in place of the original value implementing Marshaler.
38 //
39 // If an error is returned by MarshalYAML, the marshaling procedure stops
40 // and returns with the provided error.
41 type Marshaler interface {
42         MarshalYAML() (interface{}, error)
43 }
44
45 // Unmarshal decodes the first document found within the in byte slice
46 // and assigns decoded values into the out value.
47 //
48 // Maps and pointers (to a struct, string, int, etc) are accepted as out
49 // values. If an internal pointer within a struct is not initialized,
50 // the yaml package will initialize it if necessary for unmarshalling
51 // the provided data. The out parameter must not be nil.
52 //
53 // The type of the decoded values should be compatible with the respective
54 // values in out. If one or more values cannot be decoded due to a type
55 // mismatches, decoding continues partially until the end of the YAML
56 // content, and a *yaml.TypeError is returned with details for all
57 // missed values.
58 //
59 // Struct fields are only unmarshalled if they are exported (have an
60 // upper case first letter), and are unmarshalled using the field name
61 // lowercased as the default key. Custom keys may be defined via the
62 // "yaml" name in the field tag: the content preceding the first comma
63 // is used as the key, and the following comma-separated options are
64 // used to tweak the marshalling process (see Marshal).
65 // Conflicting names result in a runtime error.
66 //
67 // For example:
68 //
69 //     type T struct {
70 //         F int `yaml:"a,omitempty"`
71 //         B int
72 //     }
73 //     var t T
74 //     yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
75 //
76 // See the documentation of Marshal for the format of tags and a list of
77 // supported tag options.
78 //
79 func Unmarshal(in []byte, out interface{}) (err error) {
80         defer handleErr(&err)
81         d := newDecoder()
82         p := newParser(in)
83         defer p.destroy()
84         node := p.parse()
85         if node != nil {
86                 v := reflect.ValueOf(out)
87                 if v.Kind() == reflect.Ptr && !v.IsNil() {
88                         v = v.Elem()
89                 }
90                 d.unmarshal(node, v)
91         }
92         if len(d.terrors) > 0 {
93                 return &TypeError{d.terrors}
94         }
95         return nil
96 }
97
98 // Marshal serializes the value provided into a YAML document. The structure
99 // of the generated document will reflect the structure of the value itself.
100 // Maps and pointers (to struct, string, int, etc) are accepted as the in value.
101 //
102 // Struct fields are only unmarshalled if they are exported (have an upper case
103 // first letter), and are unmarshalled using the field name lowercased as the
104 // default key. Custom keys may be defined via the "yaml" name in the field
105 // tag: the content preceding the first comma is used as the key, and the
106 // following comma-separated options are used to tweak the marshalling process.
107 // Conflicting names result in a runtime error.
108 //
109 // The field tag format accepted is:
110 //
111 //     `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
112 //
113 // The following flags are currently supported:
114 //
115 //     omitempty    Only include the field if it's not set to the zero
116 //                  value for the type or to empty slices or maps.
117 //                  Does not apply to zero valued structs.
118 //
119 //     flow         Marshal using a flow style (useful for structs,
120 //                  sequences and maps).
121 //
122 //     inline       Inline the field, which must be a struct or a map,
123 //                  causing all of its fields or keys to be processed as if
124 //                  they were part of the outer struct. For maps, keys must
125 //                  not conflict with the yaml keys of other struct fields.
126 //
127 // In addition, if the key is "-", the field is ignored.
128 //
129 // For example:
130 //
131 //     type T struct {
132 //         F int "a,omitempty"
133 //         B int
134 //     }
135 //     yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
136 //     yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
137 //
138 func Marshal(in interface{}) (out []byte, err error) {
139         defer handleErr(&err)
140         e := newEncoder()
141         defer e.destroy()
142         e.marshal("", reflect.ValueOf(in))
143         e.finish()
144         out = e.out
145         return
146 }
147
148 func handleErr(err *error) {
149         if v := recover(); v != nil {
150                 if e, ok := v.(yamlError); ok {
151                         *err = e.err
152                 } else {
153                         panic(v)
154                 }
155         }
156 }
157
158 type yamlError struct {
159         err error
160 }
161
162 func fail(err error) {
163         panic(yamlError{err})
164 }
165
166 func failf(format string, args ...interface{}) {
167         panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
168 }
169
170 // A TypeError is returned by Unmarshal when one or more fields in
171 // the YAML document cannot be properly decoded into the requested
172 // types. When this error is returned, the value is still
173 // unmarshaled partially.
174 type TypeError struct {
175         Errors []string
176 }
177
178 func (e *TypeError) Error() string {
179         return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))
180 }
181
182 // --------------------------------------------------------------------------
183 // Maintain a mapping of keys to structure field indexes
184
185 // The code in this section was copied from mgo/bson.
186
187 // structInfo holds details for the serialization of fields of
188 // a given struct.
189 type structInfo struct {
190         FieldsMap  map[string]fieldInfo
191         FieldsList []fieldInfo
192
193         // InlineMap is the number of the field in the struct that
194         // contains an ,inline map, or -1 if there's none.
195         InlineMap int
196 }
197
198 type fieldInfo struct {
199         Key       string
200         Num       int
201         OmitEmpty bool
202         Flow      bool
203
204         // Inline holds the field index if the field is part of an inlined struct.
205         Inline []int
206 }
207
208 var structMap = make(map[reflect.Type]*structInfo)
209 var fieldMapMutex sync.RWMutex
210
211 func getStructInfo(st reflect.Type) (*structInfo, error) {
212         fieldMapMutex.RLock()
213         sinfo, found := structMap[st]
214         fieldMapMutex.RUnlock()
215         if found {
216                 return sinfo, nil
217         }
218
219         n := st.NumField()
220         fieldsMap := make(map[string]fieldInfo)
221         fieldsList := make([]fieldInfo, 0, n)
222         inlineMap := -1
223         for i := 0; i != n; i++ {
224                 field := st.Field(i)
225                 if field.PkgPath != "" && !field.Anonymous {
226                         continue // Private field
227                 }
228
229                 info := fieldInfo{Num: i}
230
231                 tag := field.Tag.Get("yaml")
232                 if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
233                         tag = string(field.Tag)
234                 }
235                 if tag == "-" {
236                         continue
237                 }
238
239                 inline := false
240                 fields := strings.Split(tag, ",")
241                 if len(fields) > 1 {
242                         for _, flag := range fields[1:] {
243                                 switch flag {
244                                 case "omitempty":
245                                         info.OmitEmpty = true
246                                 case "flow":
247                                         info.Flow = true
248                                 case "inline":
249                                         inline = true
250                                 default:
251                                         return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
252                                 }
253                         }
254                         tag = fields[0]
255                 }
256
257                 if inline {
258                         switch field.Type.Kind() {
259                         case reflect.Map:
260                                 if inlineMap >= 0 {
261                                         return nil, errors.New("Multiple ,inline maps in struct " + st.String())
262                                 }
263                                 if field.Type.Key() != reflect.TypeOf("") {
264                                         return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
265                                 }
266                                 inlineMap = info.Num
267                         case reflect.Struct:
268                                 sinfo, err := getStructInfo(field.Type)
269                                 if err != nil {
270                                         return nil, err
271                                 }
272                                 for _, finfo := range sinfo.FieldsList {
273                                         if _, found := fieldsMap[finfo.Key]; found {
274                                                 msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
275                                                 return nil, errors.New(msg)
276                                         }
277                                         if finfo.Inline == nil {
278                                                 finfo.Inline = []int{i, finfo.Num}
279                                         } else {
280                                                 finfo.Inline = append([]int{i}, finfo.Inline...)
281                                         }
282                                         fieldsMap[finfo.Key] = finfo
283                                         fieldsList = append(fieldsList, finfo)
284                                 }
285                         default:
286                                 //return nil, errors.New("Option ,inline needs a struct value or map field")
287                                 return nil, errors.New("Option ,inline needs a struct value field")
288                         }
289                         continue
290                 }
291
292                 if tag != "" {
293                         info.Key = tag
294                 } else {
295                         info.Key = strings.ToLower(field.Name)
296                 }
297
298                 if _, found = fieldsMap[info.Key]; found {
299                         msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
300                         return nil, errors.New(msg)
301                 }
302
303                 fieldsList = append(fieldsList, info)
304                 fieldsMap[info.Key] = info
305         }
306
307         sinfo = &structInfo{fieldsMap, fieldsList, inlineMap}
308
309         fieldMapMutex.Lock()
310         structMap[st] = sinfo
311         fieldMapMutex.Unlock()
312         return sinfo, nil
313 }
314
315 func isZero(v reflect.Value) bool {
316         switch v.Kind() {
317         case reflect.String:
318                 return len(v.String()) == 0
319         case reflect.Interface, reflect.Ptr:
320                 return v.IsNil()
321         case reflect.Slice:
322                 return v.Len() == 0
323         case reflect.Map:
324                 return v.Len() == 0
325         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
326                 return v.Int() == 0
327         case reflect.Float32, reflect.Float64:
328                 return v.Float() == 0
329         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
330                 return v.Uint() == 0
331         case reflect.Bool:
332                 return !v.Bool()
333         case reflect.Struct:
334                 vt := v.Type()
335                 for i := v.NumField() - 1; i >= 0; i-- {
336                         if vt.Field(i).PkgPath != "" {
337                                 continue // Private field
338                         }
339                         if !isZero(v.Field(i)) {
340                                 return false
341                         }
342                 }
343                 return true
344         }
345         return false
346 }