You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

yaml.go 20KB

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