gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

yaml.go (13885B)


      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 	"io"
     13 	"reflect"
     14 	"strings"
     15 	"sync"
     16 )
     17 
     18 // MapSlice encodes and decodes as a YAML map.
     19 // The order of keys is preserved when encoding and decoding.
     20 type MapSlice []MapItem
     21 
     22 // MapItem is an item in a MapSlice.
     23 type MapItem struct {
     24 	Key, Value interface{}
     25 }
     26 
     27 // The Unmarshaler interface may be implemented by types to customize their
     28 // behavior when being unmarshaled from a YAML document. The UnmarshalYAML
     29 // method receives a function that may be called to unmarshal the original
     30 // YAML value into a field or variable. It is safe to call the unmarshal
     31 // function parameter more than once if necessary.
     32 type Unmarshaler interface {
     33 	UnmarshalYAML(unmarshal func(interface{}) error) error
     34 }
     35 
     36 // The Marshaler interface may be implemented by types to customize their
     37 // behavior when being marshaled into a YAML document. The returned value
     38 // is marshaled in place of the original value implementing Marshaler.
     39 //
     40 // If an error is returned by MarshalYAML, the marshaling procedure stops
     41 // and returns with the provided error.
     42 type Marshaler interface {
     43 	MarshalYAML() (interface{}, error)
     44 }
     45 
     46 // Unmarshal decodes the first document found within the in byte slice
     47 // and assigns decoded values into the out value.
     48 //
     49 // Maps and pointers (to a struct, string, int, etc) are accepted as out
     50 // values. If an internal pointer within a struct is not initialized,
     51 // the yaml package will initialize it if necessary for unmarshalling
     52 // the provided data. The out parameter must not be nil.
     53 //
     54 // The type of the decoded values should be compatible with the respective
     55 // values in out. If one or more values cannot be decoded due to a type
     56 // mismatches, decoding continues partially until the end of the YAML
     57 // content, and a *yaml.TypeError is returned with details for all
     58 // missed values.
     59 //
     60 // Struct fields are only unmarshalled if they are exported (have an
     61 // upper case first letter), and are unmarshalled using the field name
     62 // lowercased as the default key. Custom keys may be defined via the
     63 // "yaml" name in the field tag: the content preceding the first comma
     64 // is used as the key, and the following comma-separated options are
     65 // used to tweak the marshalling process (see Marshal).
     66 // Conflicting names result in a runtime error.
     67 //
     68 // For example:
     69 //
     70 //     type T struct {
     71 //         F int `yaml:"a,omitempty"`
     72 //         B int
     73 //     }
     74 //     var t T
     75 //     yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
     76 //
     77 // See the documentation of Marshal for the format of tags and a list of
     78 // supported tag options.
     79 //
     80 func Unmarshal(in []byte, out interface{}) (err error) {
     81 	return unmarshal(in, out, false)
     82 }
     83 
     84 // UnmarshalStrict is like Unmarshal except that any fields that are found
     85 // in the data that do not have corresponding struct members, or mapping
     86 // keys that are duplicates, will result in
     87 // an error.
     88 func UnmarshalStrict(in []byte, out interface{}) (err error) {
     89 	return unmarshal(in, out, true)
     90 }
     91 
     92 // A Decoder reads and decodes YAML values from an input stream.
     93 type Decoder struct {
     94 	strict bool
     95 	parser *parser
     96 }
     97 
     98 // NewDecoder returns a new decoder that reads from r.
     99 //
    100 // The decoder introduces its own buffering and may read
    101 // data from r beyond the YAML values requested.
    102 func NewDecoder(r io.Reader) *Decoder {
    103 	return &Decoder{
    104 		parser: newParserFromReader(r),
    105 	}
    106 }
    107 
    108 // SetStrict sets whether strict decoding behaviour is enabled when
    109 // decoding items in the data (see UnmarshalStrict). By default, decoding is not strict.
    110 func (dec *Decoder) SetStrict(strict bool) {
    111 	dec.strict = strict
    112 }
    113 
    114 // Decode reads the next YAML-encoded value from its input
    115 // and stores it in the value pointed to by v.
    116 //
    117 // See the documentation for Unmarshal for details about the
    118 // conversion of YAML into a Go value.
    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 // Marshal serializes the value provided into a YAML document. The structure
    157 // of the generated document will reflect the structure of the value itself.
    158 // Maps and pointers (to struct, string, int, etc) are accepted as the in value.
    159 //
    160 // Struct fields are only marshalled if they are exported (have an upper case
    161 // first letter), and are marshalled using the field name lowercased as the
    162 // default key. Custom keys may be defined via the "yaml" name in the field
    163 // tag: the content preceding the first comma is used as the key, and the
    164 // following comma-separated options are used to tweak the marshalling process.
    165 // Conflicting names result in a runtime error.
    166 //
    167 // The field tag format accepted is:
    168 //
    169 //     `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
    170 //
    171 // The following flags are currently supported:
    172 //
    173 //     omitempty    Only include the field if it's not set to the zero
    174 //                  value for the type or to empty slices or maps.
    175 //                  Zero valued structs will be omitted if all their public
    176 //                  fields are zero, unless they implement an IsZero
    177 //                  method (see the IsZeroer interface type), in which
    178 //                  case the field will be excluded if IsZero returns true.
    179 //
    180 //     flow         Marshal using a flow style (useful for structs,
    181 //                  sequences and maps).
    182 //
    183 //     inline       Inline the field, which must be a struct or a map,
    184 //                  causing all of its fields or keys to be processed as if
    185 //                  they were part of the outer struct. For maps, keys must
    186 //                  not conflict with the yaml keys of other struct fields.
    187 //
    188 // In addition, if the key is "-", the field is ignored.
    189 //
    190 // For example:
    191 //
    192 //     type T struct {
    193 //         F int `yaml:"a,omitempty"`
    194 //         B int
    195 //     }
    196 //     yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
    197 //     yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
    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 // An Encoder writes YAML values to an output stream.
    210 type Encoder struct {
    211 	encoder *encoder
    212 }
    213 
    214 // NewEncoder returns a new encoder that writes to w.
    215 // The Encoder should be closed after use to flush all data
    216 // to w.
    217 func NewEncoder(w io.Writer) *Encoder {
    218 	return &Encoder{
    219 		encoder: newEncoderWithWriter(w),
    220 	}
    221 }
    222 
    223 // Encode writes the YAML encoding of v to the stream.
    224 // If multiple items are encoded to the stream, the
    225 // second and subsequent document will be preceded
    226 // with a "---" document separator, but the first will not.
    227 //
    228 // See the documentation for Marshal for details about the conversion of Go
    229 // values to YAML.
    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 // Close closes the encoder by writing any remaining data.
    237 // It does not write a stream terminating string "...".
    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 // A TypeError is returned by Unmarshal when one or more fields in
    267 // the YAML document cannot be properly decoded into the requested
    268 // types. When this error is returned, the value is still
    269 // unmarshaled partially.
    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 // Maintain a mapping of keys to structure field indexes
    280 
    281 // The code in this section was copied from mgo/bson.
    282 
    283 // structInfo holds details for the serialization of fields of
    284 // a given struct.
    285 type structInfo struct {
    286 	FieldsMap  map[string]fieldInfo
    287 	FieldsList []fieldInfo
    288 
    289 	// InlineMap is the number of the field in the struct that
    290 	// contains an ,inline map, or -1 if there's none.
    291 	InlineMap int
    292 }
    293 
    294 type fieldInfo struct {
    295 	Key       string
    296 	Num       int
    297 	OmitEmpty bool
    298 	Flow      bool
    299 	// Id holds the unique field identifier, so we can cheaply
    300 	// check for field duplicates without maintaining an extra map.
    301 	Id int
    302 
    303 	// Inline holds the field index if the field is part of an inlined struct.
    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 // Private field
    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 				//return nil, errors.New("Option ,inline needs a struct value or map field")
    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 // IsZeroer is used to check whether an object is zero to
    421 // determine whether it should be omitted when marshaling
    422 // with the omitempty flag. One notable implementation
    423 // is time.Time.
    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 // Private field
    458 			}
    459 			if !isZero(v.Field(i)) {
    460 				return false
    461 			}
    462 		}
    463 		return true
    464 	}
    465 	return false
    466 }
    467 
    468 // FutureLineWrap globally disables line wrapping when encoding long strings.
    469 // This is a temporary and thus deprecated method introduced to faciliate
    470 // migration towards v3, which offers more control of line lengths on
    471 // individual encodings, and has a default matching the behavior introduced
    472 // by this function.
    473 //
    474 // The default formatting of v2 was erroneously changed in v2.3.0 and reverted
    475 // in v2.4.0, at which point this function was introduced to help migration.
    476 func FutureLineWrap() {
    477 	disableLineWrapping = true
    478 }