gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/yaml/yaml.go (about)

     1  //
     2  // Copyright (c) 2011-2019 Canonical Ltd
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  // Package yaml implements YAML support for the Go language.
    17  //
    18  // Source code and other details for the project are available at GitHub:
    19  //
    20  //   https://github.com/go-yaml/yaml
    21  //
    22  package yaml
    23  
    24  import (
    25  	"errors"
    26  	"fmt"
    27  	"io"
    28  	"reflect"
    29  	"strings"
    30  	"sync"
    31  	"unicode/utf8"
    32  )
    33  
    34  // The Unmarshaler interface may be implemented by types to customize their
    35  // behavior when being unmarshaled from a YAML document.
    36  type Unmarshaler interface {
    37  	UnmarshalYAML(value *Node) error
    38  }
    39  
    40  type ScalarUnmarshaler interface {
    41  	UnmarshalYAMLScalar(n *Node) error
    42  }
    43  
    44  type MappingUnmarshaler interface {
    45  	UnmarshalYAMLMapping(n *Node) error
    46  }
    47  
    48  type SequenceUnmarshaler interface {
    49  	UnmarshalYAMLSequence(n *Node) error
    50  }
    51  
    52  type EntryUnmarshaler interface {
    53  	UnmarshalYAMLEntry(key *Node, value *Node) (ok bool, err error)
    54  }
    55  
    56  type ElemUnmarshaler interface {
    57  	UnmarshalYAMLElem(elem *Node) error
    58  }
    59  
    60  type obsoleteUnmarshaler interface {
    61  	UnmarshalYAML(unmarshal func(interface{}) error) error
    62  }
    63  
    64  // The Marshaler interface may be implemented by types to customize their
    65  // behavior when being marshaled into a YAML document. The returned value
    66  // is marshaled in place of the original value implementing Marshaler.
    67  //
    68  // If an error is returned by MarshalYAML, the marshaling procedure stops
    69  // and returns with the provided error.
    70  type Marshaler interface {
    71  	MarshalYAML() (interface{}, error)
    72  }
    73  
    74  // Unmarshal decodes the first document found within the in byte slice
    75  // and assigns decoded values into the out value.
    76  //
    77  // Maps and pointers (to a struct, string, int, etc) are accepted as out
    78  // values. If an internal pointer within a struct is not initialized,
    79  // the yaml package will initialize it if necessary for unmarshalling
    80  // the provided data. The out parameter must not be nil.
    81  //
    82  // The type of the decoded values should be compatible with the respective
    83  // values in out. If one or more values cannot be decoded due to a type
    84  // mismatches, decoding continues partially until the end of the YAML
    85  // content, and a *yaml.TypeError is returned with details for all
    86  // missed values.
    87  //
    88  // Struct fields are only unmarshalled if they are exported (have an
    89  // upper case first letter), and are unmarshalled using the field name
    90  // lowercased as the default key. Custom keys may be defined via the
    91  // "yaml" name in the field tag: the content preceding the first comma
    92  // is used as the key, and the following comma-separated options are
    93  // used to tweak the marshalling process (see Marshal).
    94  // Conflicting names result in a runtime error.
    95  //
    96  // For example:
    97  //
    98  //     type T struct {
    99  //         F int `yaml:"a,omitempty"`
   100  //         B int
   101  //     }
   102  //     var t T
   103  //     yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
   104  //
   105  // See the documentation of Marshal for the format of tags and a list of
   106  // supported tag options.
   107  //
   108  func Unmarshal(in []byte, out interface{}) (err error) {
   109  	return unmarshal(in, out, false)
   110  }
   111  
   112  // A Decoder reads and decodes YAML values from an input stream.
   113  type Decoder struct {
   114  	parser      *parser
   115  	knownFields bool
   116  }
   117  
   118  // NewDecoder returns a new decoder that reads from r.
   119  //
   120  // The decoder introduces its own buffering and may read
   121  // data from r beyond the YAML values requested.
   122  func NewDecoder(r io.Reader) *Decoder {
   123  	return &Decoder{
   124  		parser: newParserFromReader(r),
   125  	}
   126  }
   127  
   128  // KnownFields ensures that the keys in decoded mappings to
   129  // exist as fields in the struct being decoded into.
   130  func (dec *Decoder) KnownFields(enable bool) {
   131  	dec.knownFields = enable
   132  }
   133  
   134  // Decode reads the next YAML-encoded value from its input
   135  // and stores it in the value pointed to by v.
   136  //
   137  // See the documentation for Unmarshal for details about the
   138  // conversion of YAML into a Go value.
   139  func (dec *Decoder) Decode(v interface{}) (err error) {
   140  	d := newDecoder()
   141  	d.knownFields = dec.knownFields
   142  	defer handleErr(&err)
   143  	node := dec.parser.parse()
   144  	if node == nil {
   145  		return io.EOF
   146  	}
   147  	out := reflect.ValueOf(v)
   148  	if out.Kind() == reflect.Ptr && !out.IsNil() {
   149  		out = out.Elem()
   150  	}
   151  	d.unmarshal(node, out)
   152  	if len(d.terrors) > 0 {
   153  		return &TypeError{d.terrors}
   154  	}
   155  	return nil
   156  }
   157  
   158  // Decode decodes the node and stores its data into the value pointed to by v.
   159  //
   160  // See the documentation for Unmarshal for details about the
   161  // conversion of YAML into a Go value.
   162  func (n *Node) Decode(v interface{}) (err error) {
   163  	d := newDecoder()
   164  	defer handleErr(&err)
   165  	out := reflect.ValueOf(v)
   166  	if out.Kind() == reflect.Ptr && !out.IsNil() {
   167  		out = out.Elem()
   168  	}
   169  	d.unmarshal(n, out)
   170  	if len(d.terrors) > 0 {
   171  		return &TypeError{d.terrors}
   172  	}
   173  	return nil
   174  }
   175  
   176  func unmarshal(in []byte, out interface{}, strict bool) (err error) {
   177  	defer handleErr(&err)
   178  	d := newDecoder()
   179  	p := newParser(in)
   180  	defer p.destroy()
   181  	node := p.parse()
   182  	if node != nil {
   183  		v := reflect.ValueOf(out)
   184  		if v.Kind() == reflect.Ptr && !v.IsNil() {
   185  			v = v.Elem()
   186  		}
   187  		d.unmarshal(node, v)
   188  	}
   189  	if len(d.terrors) > 0 {
   190  		return &TypeError{d.terrors}
   191  	}
   192  	return nil
   193  }
   194  
   195  // Marshal serializes the value provided into a YAML document. The structure
   196  // of the generated document will reflect the structure of the value itself.
   197  // Maps and pointers (to struct, string, int, etc) are accepted as the in value.
   198  //
   199  // Struct fields are only marshalled if they are exported (have an upper case
   200  // first letter), and are marshalled using the field name lowercased as the
   201  // default key. Custom keys may be defined via the "yaml" name in the field
   202  // tag: the content preceding the first comma is used as the key, and the
   203  // following comma-separated options are used to tweak the marshalling process.
   204  // Conflicting names result in a runtime error.
   205  //
   206  // The field tag format accepted is:
   207  //
   208  //     `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
   209  //
   210  // The following flags are currently supported:
   211  //
   212  //     omitempty    Only include the field if it's not set to the zero
   213  //                  value for the type or to empty slices or maps.
   214  //                  Zero valued structs will be omitted if all their public
   215  //                  fields are zero, unless they implement an IsZero
   216  //                  method (see the IsZeroer interface type), in which
   217  //                  case the field will be excluded if IsZero returns true.
   218  //
   219  //     flow         Marshal using a flow style (useful for structs,
   220  //                  sequences and maps).
   221  //
   222  //     inline       Inline the field, which must be a struct or a map,
   223  //                  causing all of its fields or keys to be processed as if
   224  //                  they were part of the outer struct. For maps, keys must
   225  //                  not conflict with the yaml keys of other struct fields.
   226  //
   227  // In addition, if the key is "-", the field is ignored.
   228  //
   229  // For example:
   230  //
   231  //     type T struct {
   232  //         F int `yaml:"a,omitempty"`
   233  //         B int
   234  //     }
   235  //     yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
   236  //     yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
   237  //
   238  func Marshal(in interface{}) (out []byte, err error) {
   239  	defer handleErr(&err)
   240  	e := newEncoder()
   241  	defer e.destroy()
   242  	e.marshalDoc("", reflect.ValueOf(in))
   243  	e.finish()
   244  	out = e.out
   245  	return
   246  }
   247  
   248  // An Encoder writes YAML values to an output stream.
   249  type Encoder struct {
   250  	encoder *encoder
   251  }
   252  
   253  // NewEncoder returns a new encoder that writes to w.
   254  // The Encoder should be closed after use to flush all data
   255  // to w.
   256  func NewEncoder(w io.Writer) *Encoder {
   257  	return &Encoder{
   258  		encoder: newEncoderWithWriter(w),
   259  	}
   260  }
   261  
   262  // Encode writes the YAML encoding of v to the stream.
   263  // If multiple items are encoded to the stream, the
   264  // second and subsequent document will be preceded
   265  // with a "---" document separator, but the first will not.
   266  //
   267  // See the documentation for Marshal for details about the conversion of Go
   268  // values to YAML.
   269  func (e *Encoder) Encode(v interface{}) (err error) {
   270  	defer handleErr(&err)
   271  	e.encoder.marshalDoc("", reflect.ValueOf(v))
   272  	return nil
   273  }
   274  
   275  // Encode encodes value v and stores its representation in n.
   276  //
   277  // See the documentation for Marshal for details about the
   278  // conversion of Go values into YAML.
   279  func (n *Node) Encode(v interface{}) (err error) {
   280  	defer handleErr(&err)
   281  	e := newEncoder()
   282  	defer e.destroy()
   283  	e.marshalDoc("", reflect.ValueOf(v))
   284  	e.finish()
   285  	p := newParser(e.out)
   286  	p.textless = true
   287  	defer p.destroy()
   288  	doc := p.parse()
   289  	*n = *doc.Content[0]
   290  	return nil
   291  }
   292  
   293  // SetIndent changes the used indentation used when encoding.
   294  func (e *Encoder) SetIndent(spaces int) {
   295  	if spaces < 0 {
   296  		panic("yaml: cannot indent to a negative number of spaces")
   297  	}
   298  	e.encoder.indent = spaces
   299  }
   300  
   301  // Close closes the encoder by writing any remaining data.
   302  // It does not write a stream terminating string "...".
   303  func (e *Encoder) Close() (err error) {
   304  	defer handleErr(&err)
   305  	e.encoder.finish()
   306  	return nil
   307  }
   308  
   309  func handleErr(err *error) {
   310  	if v := recover(); v != nil {
   311  		if e, ok := v.(yamlError); ok {
   312  			*err = e.err
   313  		} else {
   314  			panic(v)
   315  		}
   316  	}
   317  }
   318  
   319  type yamlError struct {
   320  	err error
   321  }
   322  
   323  func fail(err error) {
   324  	panic(yamlError{err})
   325  }
   326  
   327  func failf(format string, args ...interface{}) {
   328  	panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
   329  }
   330  
   331  // A TypeError is returned by Unmarshal when one or more fields in
   332  // the YAML document cannot be properly decoded into the requested
   333  // types. When this error is returned, the value is still
   334  // unmarshaled partially.
   335  type TypeError struct {
   336  	Errors []string
   337  }
   338  
   339  func (e *TypeError) Error() string {
   340  	return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))
   341  }
   342  
   343  type Kind uint32
   344  
   345  const (
   346  	DocumentNode Kind = 1 << iota
   347  	SequenceNode
   348  	MappingNode
   349  	ScalarNode
   350  	AliasNode
   351  )
   352  
   353  type Style uint32
   354  
   355  const (
   356  	TaggedStyle Style = 1 << iota
   357  	DoubleQuotedStyle
   358  	SingleQuotedStyle
   359  	LiteralStyle
   360  	FoldedStyle
   361  	FlowStyle
   362  )
   363  
   364  // Node represents an element in the YAML document hierarchy. While documents
   365  // are typically encoded and decoded into higher level types, such as structs
   366  // and maps, Node is an intermediate representation that allows detailed
   367  // control over the content being decoded or encoded.
   368  //
   369  // It's worth noting that although Node offers access into details such as
   370  // line numbers, colums, and comments, the content when re-encoded will not
   371  // have its original textual representation preserved. An effort is made to
   372  // render the data plesantly, and to preserve comments near the data they
   373  // describe, though.
   374  //
   375  // Values that make use of the Node type interact with the yaml package in the
   376  // same way any other type would do, by encoding and decoding yaml data
   377  // directly or indirectly into them.
   378  //
   379  // For example:
   380  //
   381  //     var person struct {
   382  //             Name    string
   383  //             Address yaml.Node
   384  //     }
   385  //     err := yaml.Unmarshal(data, &person)
   386  // 
   387  // Or by itself:
   388  //
   389  //     var person Node
   390  //     err := yaml.Unmarshal(data, &person)
   391  //
   392  type Node struct {
   393  	// Kind defines whether the node is a document, a mapping, a sequence,
   394  	// a scalar value, or an alias to another node. The specific data type of
   395  	// scalar nodes may be obtained via the ShortTag and LongTag methods.
   396  	Kind  Kind
   397  
   398  	// Style allows customizing the apperance of the node in the tree.
   399  	Style Style
   400  
   401  	// Tag holds the YAML tag defining the data type for the value.
   402  	// When decoding, this field will always be set to the resolved tag,
   403  	// even when it wasn't explicitly provided in the YAML content.
   404  	// When encoding, if this field is unset the value type will be
   405  	// implied from the node properties, and if it is set, it will only
   406  	// be serialized into the representation if TaggedStyle is used or
   407  	// the implicit tag diverges from the provided one.
   408  	Tag string
   409  
   410  	// Value holds the unescaped and unquoted represenation of the value.
   411  	Value string
   412  
   413  	// Anchor holds the anchor name for this node, which allows aliases to point to it.
   414  	Anchor string
   415  
   416  	// Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
   417  	Alias *Node
   418  
   419  	// Content holds contained nodes for documents, mappings, and sequences.
   420  	Content []*Node
   421  
   422  	// HeadComment holds any comments in the lines preceding the node and
   423  	// not separated by an empty line.
   424  	HeadComment string
   425  
   426  	// LineComment holds any comments at the end of the line where the node is in.
   427  	LineComment string
   428  
   429  	// FootComment holds any comments following the node and before empty lines.
   430  	FootComment string
   431  
   432  	// Line and Column hold the node position in the decoded YAML text.
   433  	// These fields are not respected when encoding the node.
   434  	Line   int
   435  	Column int
   436  }
   437  
   438  // IsZero returns whether the node has all of its fields unset.
   439  func (n *Node) IsZero() bool {
   440  	return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&
   441  		n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
   442  }
   443  
   444  
   445  // LongTag returns the long form of the tag that indicates the data type for
   446  // the node. If the Tag field isn't explicitly defined, one will be computed
   447  // based on the node properties.
   448  func (n *Node) LongTag() string {
   449  	return longTag(n.ShortTag())
   450  }
   451  
   452  // ShortTag returns the short form of the YAML tag that indicates data type for
   453  // the node. If the Tag field isn't explicitly defined, one will be computed
   454  // based on the node properties.
   455  func (n *Node) ShortTag() string {
   456  	if n.indicatedString() {
   457  		return strTag
   458  	}
   459  	if n.Tag == "" || n.Tag == "!" {
   460  		switch n.Kind {
   461  		case MappingNode:
   462  			return mapTag
   463  		case SequenceNode:
   464  			return seqTag
   465  		case AliasNode:
   466  			if n.Alias != nil {
   467  				return n.Alias.ShortTag()
   468  			}
   469  		case ScalarNode:
   470  			tag, _ := resolve("", n.Value)
   471  			return tag
   472  		case 0:
   473  			// Special case to make the zero value convenient.
   474  			if n.IsZero() {
   475  				return nullTag
   476  			}
   477  		}
   478  		return ""
   479  	}
   480  	return shortTag(n.Tag)
   481  }
   482  
   483  func (n *Node) indicatedString() bool {
   484  	return n.Kind == ScalarNode &&
   485  		(shortTag(n.Tag) == strTag ||
   486  			(n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
   487  }
   488  
   489  // SetString is a convenience function that sets the node to a string value
   490  // and defines its style in a pleasant way depending on its content.
   491  func (n *Node) SetString(s string) {
   492  	n.Kind = ScalarNode
   493  	if utf8.ValidString(s) {
   494  		n.Value = s
   495  		n.Tag = strTag
   496  	} else {
   497  		n.Value = encodeBase64(s)
   498  		n.Tag = binaryTag
   499  	}
   500  	if strings.Contains(n.Value, "\n") {
   501  		n.Style = LiteralStyle
   502  	}
   503  }
   504  
   505  // --------------------------------------------------------------------------
   506  // Maintain a mapping of keys to structure field indexes
   507  
   508  // The code in this section was copied from mgo/bson.
   509  
   510  // structInfo holds details for the serialization of fields of
   511  // a given struct.
   512  type structInfo struct {
   513  	FieldsMap  map[string]fieldInfo
   514  	FieldsList []fieldInfo
   515  
   516  	// InlineMap is the number of the field in the struct that
   517  	// contains an ,inline map, or -1 if there's none.
   518  	InlineMap int
   519  
   520  	// InlineUnmarshalers holds indexes to inlined fields that
   521  	// contain unmarshaler values.
   522  	InlineUnmarshalers [][]int
   523  
   524  	// InlineEntryUnmarshalers holds indexes to inlined fields
   525  	// that contain entryUnmarshaler values.
   526  	InlineEntryUnmarshalers [][]int
   527  }
   528  
   529  type fieldInfo struct {
   530  	Key       string
   531  	Num       int
   532  	OmitEmpty bool
   533  	Flow      bool
   534  	// Id holds the unique field identifier, so we can cheaply
   535  	// check for field duplicates without maintaining an extra map.
   536  	Id int
   537  
   538  	// Inline holds the field index if the field is part of an inlined struct.
   539  	Inline []int
   540  }
   541  
   542  var structMap = make(map[reflect.Type]*structInfo)
   543  var fieldMapMutex sync.RWMutex
   544  var (
   545  	unmarshalerType      reflect.Type
   546  	entryUnmarshalerType reflect.Type
   547  )
   548  
   549  func init() {
   550  	var v Unmarshaler
   551  	unmarshalerType = reflect.ValueOf(&v).Elem().Type()
   552  }
   553  
   554  func init() {
   555  	var v EntryUnmarshaler
   556  	entryUnmarshalerType = reflect.ValueOf(&v).Elem().Type()
   557  }
   558  
   559  func getStructInfo(st reflect.Type) (*structInfo, error) {
   560  	fieldMapMutex.RLock()
   561  	sinfo, found := structMap[st]
   562  	fieldMapMutex.RUnlock()
   563  	if found {
   564  		return sinfo, nil
   565  	}
   566  
   567  	n := st.NumField()
   568  	fieldsMap := make(map[string]fieldInfo)
   569  	fieldsList := make([]fieldInfo, 0, n)
   570  	inlineMap := -1
   571  	inlineUnmarshalers := [][]int(nil)
   572  	inlineEntryUnmarshalers := [][]int(nil)
   573  
   574  	if reflect.PtrTo(st).Implements(entryUnmarshalerType) {
   575  		inlineEntryUnmarshalers = append(inlineEntryUnmarshalers, nil)
   576  	}
   577  
   578  	for i := 0; i != n; i++ {
   579  		field := st.Field(i)
   580  		if field.PkgPath != "" && !field.Anonymous {
   581  			continue // Private field
   582  		}
   583  
   584  		info := fieldInfo{Num: i}
   585  
   586  		tag := field.Tag.Get("yaml")
   587  		if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
   588  			tag = string(field.Tag)
   589  		}
   590  		if tag == "-" {
   591  			continue
   592  		}
   593  
   594  		inline := false
   595  		fields := strings.Split(tag, ",")
   596  		if len(fields) > 1 {
   597  			for _, flag := range fields[1:] {
   598  				switch flag {
   599  				case "omitempty":
   600  					info.OmitEmpty = true
   601  				case "flow":
   602  					info.Flow = true
   603  				case "inline":
   604  					inline = true
   605  				default:
   606  					return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
   607  				}
   608  			}
   609  			tag = fields[0]
   610  		}
   611  
   612  		if inline {
   613  			switch field.Type.Kind() {
   614  			case reflect.Map:
   615  				if inlineMap >= 0 {
   616  					return nil, errors.New("multiple ,inline maps in struct " + st.String())
   617  				}
   618  				if field.Type.Key() != reflect.TypeOf("") {
   619  					return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
   620  				}
   621  				inlineMap = info.Num
   622  			case reflect.Struct, reflect.Ptr:
   623  				ftype := field.Type
   624  				for ftype.Kind() == reflect.Ptr {
   625  					ftype = ftype.Elem()
   626  				}
   627  				if ftype.Kind() != reflect.Struct {
   628  					return nil, errors.New("option ,inline may only be used on a struct or map field")
   629  				}
   630  				if reflect.PtrTo(ftype).Implements(unmarshalerType) {
   631  					inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
   632  				} else {
   633  					sinfo, err := getStructInfo(ftype)
   634  					if err != nil {
   635  						return nil, err
   636  					}
   637  					for _, index := range sinfo.InlineUnmarshalers {
   638  						inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
   639  					}
   640  					for _, index := range sinfo.InlineEntryUnmarshalers {
   641  						inlineEntryUnmarshalers = append(inlineEntryUnmarshalers, append([]int{i}, index...))
   642  					}
   643  					for _, finfo := range sinfo.FieldsList {
   644  						if _, found := fieldsMap[finfo.Key]; found {
   645  							msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
   646  							return nil, errors.New(msg)
   647  						}
   648  						if finfo.Inline == nil {
   649  							finfo.Inline = []int{i, finfo.Num}
   650  						} else {
   651  							finfo.Inline = append([]int{i}, finfo.Inline...)
   652  						}
   653  						finfo.Id = len(fieldsList)
   654  						fieldsMap[finfo.Key] = finfo
   655  						fieldsList = append(fieldsList, finfo)
   656  					}
   657  				}
   658  			default:
   659  				return nil, errors.New("option ,inline may only be used on a struct or map field")
   660  			}
   661  			continue
   662  		}
   663  
   664  		if tag != "" {
   665  			info.Key = tag
   666  		} else {
   667  			info.Key = strings.ToLower(field.Name)
   668  		}
   669  
   670  		if _, found = fieldsMap[info.Key]; found {
   671  			msg := "duplicated key '" + info.Key + "' in struct " + st.String()
   672  			return nil, errors.New(msg)
   673  		}
   674  
   675  		info.Id = len(fieldsList)
   676  		fieldsList = append(fieldsList, info)
   677  		fieldsMap[info.Key] = info
   678  	}
   679  
   680  	sinfo = &structInfo{
   681  		FieldsMap:               fieldsMap,
   682  		FieldsList:              fieldsList,
   683  		InlineMap:               inlineMap,
   684  		InlineUnmarshalers:      inlineUnmarshalers,
   685  		InlineEntryUnmarshalers: inlineEntryUnmarshalers,
   686  	}
   687  
   688  	fieldMapMutex.Lock()
   689  	structMap[st] = sinfo
   690  	fieldMapMutex.Unlock()
   691  	return sinfo, nil
   692  }
   693  
   694  // IsZeroer is used to check whether an object is zero to
   695  // determine whether it should be omitted when marshaling
   696  // with the omitempty flag. One notable implementation
   697  // is time.Time.
   698  type IsZeroer interface {
   699  	IsZero() bool
   700  }
   701  
   702  func isZero(v reflect.Value) bool {
   703  	kind := v.Kind()
   704  	if z, ok := v.Interface().(IsZeroer); ok {
   705  		if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
   706  			return true
   707  		}
   708  		return z.IsZero()
   709  	}
   710  	switch kind {
   711  	case reflect.String:
   712  		return len(v.String()) == 0
   713  	case reflect.Interface, reflect.Ptr:
   714  		return v.IsNil()
   715  	case reflect.Slice:
   716  		return v.Len() == 0
   717  	case reflect.Map:
   718  		return v.Len() == 0
   719  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   720  		return v.Int() == 0
   721  	case reflect.Float32, reflect.Float64:
   722  		return v.Float() == 0
   723  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   724  		return v.Uint() == 0
   725  	case reflect.Bool:
   726  		return !v.Bool()
   727  	case reflect.Struct:
   728  		vt := v.Type()
   729  		for i := v.NumField() - 1; i >= 0; i-- {
   730  			if vt.Field(i).PkgPath != "" {
   731  				continue // Private field
   732  			}
   733  			if !isZero(v.Field(i)) {
   734  				return false
   735  			}
   736  		}
   737  		return true
   738  	}
   739  	return false
   740  }