decode_meta.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package toml
  2. import "strings"
  3. // MetaData allows access to meta information about TOML data that may not be
  4. // inferable via reflection. In particular, whether a key has been defined and
  5. // the TOML type of a key.
  6. type MetaData struct {
  7. mapping map[string]interface{}
  8. types map[string]tomlType
  9. keys []Key
  10. decoded map[string]bool
  11. context Key // Used only during decoding.
  12. }
  13. // IsDefined reports if the key exists in the TOML data.
  14. //
  15. // The key should be specified hierarchically, for example to access the TOML
  16. // key "a.b.c" you would use:
  17. //
  18. // IsDefined("a", "b", "c")
  19. //
  20. // IsDefined will return false if an empty key given. Keys are case sensitive.
  21. func (md *MetaData) IsDefined(key ...string) bool {
  22. if len(key) == 0 {
  23. return false
  24. }
  25. var hash map[string]interface{}
  26. var ok bool
  27. var hashOrVal interface{} = md.mapping
  28. for _, k := range key {
  29. if hash, ok = hashOrVal.(map[string]interface{}); !ok {
  30. return false
  31. }
  32. if hashOrVal, ok = hash[k]; !ok {
  33. return false
  34. }
  35. }
  36. return true
  37. }
  38. // Type returns a string representation of the type of the key specified.
  39. //
  40. // Type will return the empty string if given an empty key or a key that does
  41. // not exist. Keys are case sensitive.
  42. func (md *MetaData) Type(key ...string) string {
  43. fullkey := strings.Join(key, ".")
  44. if typ, ok := md.types[fullkey]; ok {
  45. return typ.typeString()
  46. }
  47. return ""
  48. }
  49. // Key represents any TOML key, including key groups. Use (MetaData).Keys to get
  50. // values of this type.
  51. type Key []string
  52. func (k Key) String() string { return strings.Join(k, ".") }
  53. func (k Key) maybeQuotedAll() string {
  54. var ss []string
  55. for i := range k {
  56. ss = append(ss, k.maybeQuoted(i))
  57. }
  58. return strings.Join(ss, ".")
  59. }
  60. func (k Key) maybeQuoted(i int) string {
  61. if k[i] == "" {
  62. return `""`
  63. }
  64. quote := false
  65. for _, c := range k[i] {
  66. if !isBareKeyChar(c) {
  67. quote = true
  68. break
  69. }
  70. }
  71. if quote {
  72. return `"` + quotedReplacer.Replace(k[i]) + `"`
  73. }
  74. return k[i]
  75. }
  76. func (k Key) add(piece string) Key {
  77. newKey := make(Key, len(k)+1)
  78. copy(newKey, k)
  79. newKey[len(k)] = piece
  80. return newKey
  81. }
  82. // Keys returns a slice of every key in the TOML data, including key groups.
  83. //
  84. // Each key is itself a slice, where the first element is the top of the
  85. // hierarchy and the last is the most specific. The list will have the same
  86. // order as the keys appeared in the TOML data.
  87. //
  88. // All keys returned are non-empty.
  89. func (md *MetaData) Keys() []Key {
  90. return md.keys
  91. }
  92. // Undecoded returns all keys that have not been decoded in the order in which
  93. // they appear in the original TOML document.
  94. //
  95. // This includes keys that haven't been decoded because of a Primitive value.
  96. // Once the Primitive value is decoded, the keys will be considered decoded.
  97. //
  98. // Also note that decoding into an empty interface will result in no decoding,
  99. // and so no keys will be considered decoded.
  100. //
  101. // In this sense, the Undecoded keys correspond to keys in the TOML document
  102. // that do not have a concrete type in your representation.
  103. func (md *MetaData) Undecoded() []Key {
  104. undecoded := make([]Key, 0, len(md.keys))
  105. for _, key := range md.keys {
  106. if !md.decoded[key.String()] {
  107. undecoded = append(undecoded, key)
  108. }
  109. }
  110. return undecoded
  111. }