yaml.go 20 KB

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