OSDN Git Service

new repo
[bytom/vapor.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         return unmarshal(in, out, false)
81 }
82
83 // UnmarshalStrict is like Unmarshal except that any fields that are found
84 // in the data that do not have corresponding struct members will result in
85 // an error.
86 func UnmarshalStrict(in []byte, out interface{}) (err error) {
87         return unmarshal(in, out, true)
88 }
89
90 func unmarshal(in []byte, out interface{}, strict bool) (err error) {
91         defer handleErr(&err)
92         d := newDecoder(strict)
93         p := newParser(in)
94         defer p.destroy()
95         node := p.parse()
96         if node != nil {
97                 v := reflect.ValueOf(out)
98                 if v.Kind() == reflect.Ptr && !v.IsNil() {
99                         v = v.Elem()
100                 }
101                 d.unmarshal(node, v)
102         }
103         if len(d.terrors) > 0 {
104                 return &TypeError{d.terrors}
105         }
106         return nil
107 }
108
109 // Marshal serializes the value provided into a YAML document. The structure
110 // of the generated document will reflect the structure of the value itself.
111 // Maps and pointers (to struct, string, int, etc) are accepted as the in value.
112 //
113 // Struct fields are only unmarshalled if they are exported (have an upper case
114 // first letter), and are unmarshalled using the field name lowercased as the
115 // default key. Custom keys may be defined via the "yaml" name in the field
116 // tag: the content preceding the first comma is used as the key, and the
117 // following comma-separated options are used to tweak the marshalling process.
118 // Conflicting names result in a runtime error.
119 //
120 // The field tag format accepted is:
121 //
122 //     `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
123 //
124 // The following flags are currently supported:
125 //
126 //     omitempty    Only include the field if it's not set to the zero
127 //                  value for the type or to empty slices or maps.
128 //                  Does not apply to zero valued structs.
129 //
130 //     flow         Marshal using a flow style (useful for structs,
131 //                  sequences and maps).
132 //
133 //     inline       Inline the field, which must be a struct or a map,
134 //                  causing all of its fields or keys to be processed as if
135 //                  they were part of the outer struct. For maps, keys must
136 //                  not conflict with the yaml keys of other struct fields.
137 //
138 // In addition, if the key is "-", the field is ignored.
139 //
140 // For example:
141 //
142 //     type T struct {
143 //         F int "a,omitempty"
144 //         B int
145 //     }
146 //     yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
147 //     yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
148 //
149 func Marshal(in interface{}) (out []byte, err error) {
150         defer handleErr(&err)
151         e := newEncoder()
152         defer e.destroy()
153         e.marshal("", reflect.ValueOf(in))
154         e.finish()
155         out = e.out
156         return
157 }
158
159 func handleErr(err *error) {
160         if v := recover(); v != nil {
161                 if e, ok := v.(yamlError); ok {
162                         *err = e.err
163                 } else {
164                         panic(v)
165                 }
166         }
167 }
168
169 type yamlError struct {
170         err error
171 }
172
173 func fail(err error) {
174         panic(yamlError{err})
175 }
176
177 func failf(format string, args ...interface{}) {
178         panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
179 }
180
181 // A TypeError is returned by Unmarshal when one or more fields in
182 // the YAML document cannot be properly decoded into the requested
183 // types. When this error is returned, the value is still
184 // unmarshaled partially.
185 type TypeError struct {
186         Errors []string
187 }
188
189 func (e *TypeError) Error() string {
190         return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))
191 }
192
193 // --------------------------------------------------------------------------
194 // Maintain a mapping of keys to structure field indexes
195
196 // The code in this section was copied from mgo/bson.
197
198 // structInfo holds details for the serialization of fields of
199 // a given struct.
200 type structInfo struct {
201         FieldsMap  map[string]fieldInfo
202         FieldsList []fieldInfo
203
204         // InlineMap is the number of the field in the struct that
205         // contains an ,inline map, or -1 if there's none.
206         InlineMap int
207 }
208
209 type fieldInfo struct {
210         Key       string
211         Num       int
212         OmitEmpty bool
213         Flow      bool
214
215         // Inline holds the field index if the field is part of an inlined struct.
216         Inline []int
217 }
218
219 var structMap = make(map[reflect.Type]*structInfo)
220 var fieldMapMutex sync.RWMutex
221
222 func getStructInfo(st reflect.Type) (*structInfo, error) {
223         fieldMapMutex.RLock()
224         sinfo, found := structMap[st]
225         fieldMapMutex.RUnlock()
226         if found {
227                 return sinfo, nil
228         }
229
230         n := st.NumField()
231         fieldsMap := make(map[string]fieldInfo)
232         fieldsList := make([]fieldInfo, 0, n)
233         inlineMap := -1
234         for i := 0; i != n; i++ {
235                 field := st.Field(i)
236                 if field.PkgPath != "" && !field.Anonymous {
237                         continue // Private field
238                 }
239
240                 info := fieldInfo{Num: i}
241
242                 tag := field.Tag.Get("yaml")
243                 if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
244                         tag = string(field.Tag)
245                 }
246                 if tag == "-" {
247                         continue
248                 }
249
250                 inline := false
251                 fields := strings.Split(tag, ",")
252                 if len(fields) > 1 {
253                         for _, flag := range fields[1:] {
254                                 switch flag {
255                                 case "omitempty":
256                                         info.OmitEmpty = true
257                                 case "flow":
258                                         info.Flow = true
259                                 case "inline":
260                                         inline = true
261                                 default:
262                                         return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
263                                 }
264                         }
265                         tag = fields[0]
266                 }
267
268                 if inline {
269                         switch field.Type.Kind() {
270                         case reflect.Map:
271                                 if inlineMap >= 0 {
272                                         return nil, errors.New("Multiple ,inline maps in struct " + st.String())
273                                 }
274                                 if field.Type.Key() != reflect.TypeOf("") {
275                                         return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
276                                 }
277                                 inlineMap = info.Num
278                         case reflect.Struct:
279                                 sinfo, err := getStructInfo(field.Type)
280                                 if err != nil {
281                                         return nil, err
282                                 }
283                                 for _, finfo := range sinfo.FieldsList {
284                                         if _, found := fieldsMap[finfo.Key]; found {
285                                                 msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
286                                                 return nil, errors.New(msg)
287                                         }
288                                         if finfo.Inline == nil {
289                                                 finfo.Inline = []int{i, finfo.Num}
290                                         } else {
291                                                 finfo.Inline = append([]int{i}, finfo.Inline...)
292                                         }
293                                         fieldsMap[finfo.Key] = finfo
294                                         fieldsList = append(fieldsList, finfo)
295                                 }
296                         default:
297                                 //return nil, errors.New("Option ,inline needs a struct value or map field")
298                                 return nil, errors.New("Option ,inline needs a struct value field")
299                         }
300                         continue
301                 }
302
303                 if tag != "" {
304                         info.Key = tag
305                 } else {
306                         info.Key = strings.ToLower(field.Name)
307                 }
308
309                 if _, found = fieldsMap[info.Key]; found {
310                         msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
311                         return nil, errors.New(msg)
312                 }
313
314                 fieldsList = append(fieldsList, info)
315                 fieldsMap[info.Key] = info
316         }
317
318         sinfo = &structInfo{fieldsMap, fieldsList, inlineMap}
319
320         fieldMapMutex.Lock()
321         structMap[st] = sinfo
322         fieldMapMutex.Unlock()
323         return sinfo, nil
324 }
325
326 func isZero(v reflect.Value) bool {
327         switch v.Kind() {
328         case reflect.String:
329                 return len(v.String()) == 0
330         case reflect.Interface, reflect.Ptr:
331                 return v.IsNil()
332         case reflect.Slice:
333                 return v.Len() == 0
334         case reflect.Map:
335                 return v.Len() == 0
336         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
337                 return v.Int() == 0
338         case reflect.Float32, reflect.Float64:
339                 return v.Float() == 0
340         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
341                 return v.Uint() == 0
342         case reflect.Bool:
343                 return !v.Bool()
344         case reflect.Struct:
345                 vt := v.Type()
346                 for i := v.NumField() - 1; i >= 0; i-- {
347                         if vt.Field(i).PkgPath != "" {
348                                 continue // Private field
349                         }
350                         if !isZero(v.Field(i)) {
351                                 return false
352                         }
353                 }
354                 return true
355         }
356         return false
357 }