value.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. Copyright 2018 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package value
  14. import (
  15. "bytes"
  16. "fmt"
  17. "io"
  18. "strings"
  19. jsoniter "github.com/json-iterator/go"
  20. "gopkg.in/yaml.v2"
  21. )
  22. var (
  23. readPool = jsoniter.NewIterator(jsoniter.ConfigCompatibleWithStandardLibrary).Pool()
  24. writePool = jsoniter.NewStream(jsoniter.ConfigCompatibleWithStandardLibrary, nil, 1024).Pool()
  25. )
  26. // A Value corresponds to an 'atom' in the schema. It should return true
  27. // for at least one of the IsXXX methods below, or the value is
  28. // considered "invalid"
  29. type Value interface {
  30. // IsMap returns true if the Value is a Map, false otherwise.
  31. IsMap() bool
  32. // IsList returns true if the Value is a List, false otherwise.
  33. IsList() bool
  34. // IsBool returns true if the Value is a bool, false otherwise.
  35. IsBool() bool
  36. // IsInt returns true if the Value is a int64, false otherwise.
  37. IsInt() bool
  38. // IsFloat returns true if the Value is a float64, false
  39. // otherwise.
  40. IsFloat() bool
  41. // IsString returns true if the Value is a string, false
  42. // otherwise.
  43. IsString() bool
  44. // IsMap returns true if the Value is null, false otherwise.
  45. IsNull() bool
  46. // AsMap converts the Value into a Map (or panic if the type
  47. // doesn't allow it).
  48. AsMap() Map
  49. // AsMapUsing uses the provided allocator and converts the Value
  50. // into a Map (or panic if the type doesn't allow it).
  51. AsMapUsing(Allocator) Map
  52. // AsList converts the Value into a List (or panic if the type
  53. // doesn't allow it).
  54. AsList() List
  55. // AsListUsing uses the provided allocator and converts the Value
  56. // into a List (or panic if the type doesn't allow it).
  57. AsListUsing(Allocator) List
  58. // AsBool converts the Value into a bool (or panic if the type
  59. // doesn't allow it).
  60. AsBool() bool
  61. // AsInt converts the Value into an int64 (or panic if the type
  62. // doesn't allow it).
  63. AsInt() int64
  64. // AsFloat converts the Value into a float64 (or panic if the type
  65. // doesn't allow it).
  66. AsFloat() float64
  67. // AsString converts the Value into a string (or panic if the type
  68. // doesn't allow it).
  69. AsString() string
  70. // Unstructured converts the Value into an Unstructured interface{}.
  71. Unstructured() interface{}
  72. }
  73. // FromJSON is a helper function for reading a JSON document.
  74. func FromJSON(input []byte) (Value, error) {
  75. return FromJSONFast(input)
  76. }
  77. // FromJSONFast is a helper function for reading a JSON document.
  78. func FromJSONFast(input []byte) (Value, error) {
  79. iter := readPool.BorrowIterator(input)
  80. defer readPool.ReturnIterator(iter)
  81. return ReadJSONIter(iter)
  82. }
  83. // ToJSON is a helper function for producing a JSon document.
  84. func ToJSON(v Value) ([]byte, error) {
  85. buf := bytes.Buffer{}
  86. stream := writePool.BorrowStream(&buf)
  87. defer writePool.ReturnStream(stream)
  88. WriteJSONStream(v, stream)
  89. b := stream.Buffer()
  90. err := stream.Flush()
  91. // Help jsoniter manage its buffers--without this, the next
  92. // use of the stream is likely to require an allocation. Look
  93. // at the jsoniter stream code to understand why. They were probably
  94. // optimizing for folks using the buffer directly.
  95. stream.SetBuffer(b[:0])
  96. return buf.Bytes(), err
  97. }
  98. // ReadJSONIter reads a Value from a JSON iterator.
  99. func ReadJSONIter(iter *jsoniter.Iterator) (Value, error) {
  100. v := iter.Read()
  101. if iter.Error != nil && iter.Error != io.EOF {
  102. return nil, iter.Error
  103. }
  104. return NewValueInterface(v), nil
  105. }
  106. // WriteJSONStream writes a value into a JSON stream.
  107. func WriteJSONStream(v Value, stream *jsoniter.Stream) {
  108. stream.WriteVal(v.Unstructured())
  109. }
  110. // ToYAML marshals a value as YAML.
  111. func ToYAML(v Value) ([]byte, error) {
  112. return yaml.Marshal(v.Unstructured())
  113. }
  114. // Equals returns true iff the two values are equal.
  115. func Equals(lhs, rhs Value) bool {
  116. return EqualsUsing(HeapAllocator, lhs, rhs)
  117. }
  118. // EqualsUsing uses the provided allocator and returns true iff the two values are equal.
  119. func EqualsUsing(a Allocator, lhs, rhs Value) bool {
  120. if lhs.IsFloat() || rhs.IsFloat() {
  121. var lf float64
  122. if lhs.IsFloat() {
  123. lf = lhs.AsFloat()
  124. } else if lhs.IsInt() {
  125. lf = float64(lhs.AsInt())
  126. } else {
  127. return false
  128. }
  129. var rf float64
  130. if rhs.IsFloat() {
  131. rf = rhs.AsFloat()
  132. } else if rhs.IsInt() {
  133. rf = float64(rhs.AsInt())
  134. } else {
  135. return false
  136. }
  137. return lf == rf
  138. }
  139. if lhs.IsInt() {
  140. if rhs.IsInt() {
  141. return lhs.AsInt() == rhs.AsInt()
  142. }
  143. return false
  144. } else if rhs.IsInt() {
  145. return false
  146. }
  147. if lhs.IsString() {
  148. if rhs.IsString() {
  149. return lhs.AsString() == rhs.AsString()
  150. }
  151. return false
  152. } else if rhs.IsString() {
  153. return false
  154. }
  155. if lhs.IsBool() {
  156. if rhs.IsBool() {
  157. return lhs.AsBool() == rhs.AsBool()
  158. }
  159. return false
  160. } else if rhs.IsBool() {
  161. return false
  162. }
  163. if lhs.IsList() {
  164. if rhs.IsList() {
  165. lhsList := lhs.AsListUsing(a)
  166. defer a.Free(lhsList)
  167. rhsList := rhs.AsListUsing(a)
  168. defer a.Free(rhsList)
  169. return lhsList.EqualsUsing(a, rhsList)
  170. }
  171. return false
  172. } else if rhs.IsList() {
  173. return false
  174. }
  175. if lhs.IsMap() {
  176. if rhs.IsMap() {
  177. lhsList := lhs.AsMapUsing(a)
  178. defer a.Free(lhsList)
  179. rhsList := rhs.AsMapUsing(a)
  180. defer a.Free(rhsList)
  181. return lhsList.EqualsUsing(a, rhsList)
  182. }
  183. return false
  184. } else if rhs.IsMap() {
  185. return false
  186. }
  187. if lhs.IsNull() {
  188. if rhs.IsNull() {
  189. return true
  190. }
  191. return false
  192. } else if rhs.IsNull() {
  193. return false
  194. }
  195. // No field is set, on either objects.
  196. return true
  197. }
  198. // ToString returns a human-readable representation of the value.
  199. func ToString(v Value) string {
  200. if v.IsNull() {
  201. return "null"
  202. }
  203. switch {
  204. case v.IsFloat():
  205. return fmt.Sprintf("%v", v.AsFloat())
  206. case v.IsInt():
  207. return fmt.Sprintf("%v", v.AsInt())
  208. case v.IsString():
  209. return fmt.Sprintf("%q", v.AsString())
  210. case v.IsBool():
  211. return fmt.Sprintf("%v", v.AsBool())
  212. case v.IsList():
  213. strs := []string{}
  214. list := v.AsList()
  215. for i := 0; i < list.Length(); i++ {
  216. strs = append(strs, ToString(list.At(i)))
  217. }
  218. return "[" + strings.Join(strs, ",") + "]"
  219. case v.IsMap():
  220. strs := []string{}
  221. v.AsMap().Iterate(func(k string, v Value) bool {
  222. strs = append(strs, fmt.Sprintf("%v=%v", k, ToString(v)))
  223. return true
  224. })
  225. return strings.Join(strs, "")
  226. }
  227. // No field is set, on either objects.
  228. return "{{undefined}}"
  229. }
  230. // Less provides a total ordering for Value (so that they can be sorted, even
  231. // if they are of different types).
  232. func Less(lhs, rhs Value) bool {
  233. return Compare(lhs, rhs) == -1
  234. }
  235. // Compare provides a total ordering for Value (so that they can be
  236. // sorted, even if they are of different types). The result will be 0 if
  237. // v==rhs, -1 if v < rhs, and +1 if v > rhs.
  238. func Compare(lhs, rhs Value) int {
  239. return CompareUsing(HeapAllocator, lhs, rhs)
  240. }
  241. // CompareUsing uses the provided allocator and provides a total
  242. // ordering for Value (so that they can be sorted, even if they
  243. // are of different types). The result will be 0 if v==rhs, -1
  244. // if v < rhs, and +1 if v > rhs.
  245. func CompareUsing(a Allocator, lhs, rhs Value) int {
  246. if lhs.IsFloat() {
  247. if !rhs.IsFloat() {
  248. // Extra: compare floats and ints numerically.
  249. if rhs.IsInt() {
  250. return FloatCompare(lhs.AsFloat(), float64(rhs.AsInt()))
  251. }
  252. return -1
  253. }
  254. return FloatCompare(lhs.AsFloat(), rhs.AsFloat())
  255. } else if rhs.IsFloat() {
  256. // Extra: compare floats and ints numerically.
  257. if lhs.IsInt() {
  258. return FloatCompare(float64(lhs.AsInt()), rhs.AsFloat())
  259. }
  260. return 1
  261. }
  262. if lhs.IsInt() {
  263. if !rhs.IsInt() {
  264. return -1
  265. }
  266. return IntCompare(lhs.AsInt(), rhs.AsInt())
  267. } else if rhs.IsInt() {
  268. return 1
  269. }
  270. if lhs.IsString() {
  271. if !rhs.IsString() {
  272. return -1
  273. }
  274. return strings.Compare(lhs.AsString(), rhs.AsString())
  275. } else if rhs.IsString() {
  276. return 1
  277. }
  278. if lhs.IsBool() {
  279. if !rhs.IsBool() {
  280. return -1
  281. }
  282. return BoolCompare(lhs.AsBool(), rhs.AsBool())
  283. } else if rhs.IsBool() {
  284. return 1
  285. }
  286. if lhs.IsList() {
  287. if !rhs.IsList() {
  288. return -1
  289. }
  290. lhsList := lhs.AsListUsing(a)
  291. defer a.Free(lhsList)
  292. rhsList := rhs.AsListUsing(a)
  293. defer a.Free(rhsList)
  294. return ListCompareUsing(a, lhsList, rhsList)
  295. } else if rhs.IsList() {
  296. return 1
  297. }
  298. if lhs.IsMap() {
  299. if !rhs.IsMap() {
  300. return -1
  301. }
  302. lhsMap := lhs.AsMapUsing(a)
  303. defer a.Free(lhsMap)
  304. rhsMap := rhs.AsMapUsing(a)
  305. defer a.Free(rhsMap)
  306. return MapCompareUsing(a, lhsMap, rhsMap)
  307. } else if rhs.IsMap() {
  308. return 1
  309. }
  310. if lhs.IsNull() {
  311. if !rhs.IsNull() {
  312. return -1
  313. }
  314. return 0
  315. } else if rhs.IsNull() {
  316. return 1
  317. }
  318. // Invalid Value-- nothing is set.
  319. return 0
  320. }