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.
 
 

412 lines
12 KiB

  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package protoreflect
  5. import (
  6. "fmt"
  7. "math"
  8. )
  9. // Value is a union where only one Go type may be set at a time.
  10. // The Value is used to represent all possible values a field may take.
  11. // The following shows which Go type is used to represent each proto Kind:
  12. //
  13. // ╔════════════╤═════════════════════════════════════╗
  14. // ║ Go type │ Protobuf kind ║
  15. // ╠════════════╪═════════════════════════════════════╣
  16. // ║ bool │ BoolKind ║
  17. // ║ int32 │ Int32Kind, Sint32Kind, Sfixed32Kind ║
  18. // ║ int64 │ Int64Kind, Sint64Kind, Sfixed64Kind ║
  19. // ║ uint32 │ Uint32Kind, Fixed32Kind ║
  20. // ║ uint64 │ Uint64Kind, Fixed64Kind ║
  21. // ║ float32 │ FloatKind ║
  22. // ║ float64 │ DoubleKind ║
  23. // ║ string │ StringKind ║
  24. // ║ []byte │ BytesKind ║
  25. // ║ EnumNumber │ EnumKind ║
  26. // ║ Message │ MessageKind, GroupKind ║
  27. // ╚════════════╧═════════════════════════════════════╝
  28. //
  29. // Multiple protobuf Kinds may be represented by a single Go type if the type
  30. // can losslessly represent the information for the proto kind. For example,
  31. // Int64Kind, Sint64Kind, and Sfixed64Kind are all represented by int64,
  32. // but use different integer encoding methods.
  33. //
  34. // The List or Map types are used if the field cardinality is repeated.
  35. // A field is a List if FieldDescriptor.IsList reports true.
  36. // A field is a Map if FieldDescriptor.IsMap reports true.
  37. //
  38. // Converting to/from a Value and a concrete Go value panics on type mismatch.
  39. // For example, ValueOf("hello").Int() panics because this attempts to
  40. // retrieve an int64 from a string.
  41. type Value value
  42. // The protoreflect API uses a custom Value union type instead of interface{}
  43. // to keep the future open for performance optimizations. Using an interface{}
  44. // always incurs an allocation for primitives (e.g., int64) since it needs to
  45. // be boxed on the heap (as interfaces can only contain pointers natively).
  46. // Instead, we represent the Value union as a flat struct that internally keeps
  47. // track of which type is set. Using unsafe, the Value union can be reduced
  48. // down to 24B, which is identical in size to a slice.
  49. //
  50. // The latest compiler (Go1.11) currently suffers from some limitations:
  51. // • With inlining, the compiler should be able to statically prove that
  52. // only one of these switch cases are taken and inline one specific case.
  53. // See https://golang.org/issue/22310.
  54. // ValueOf returns a Value initialized with the concrete value stored in v.
  55. // This panics if the type does not match one of the allowed types in the
  56. // Value union.
  57. func ValueOf(v interface{}) Value {
  58. switch v := v.(type) {
  59. case nil:
  60. return Value{}
  61. case bool:
  62. return ValueOfBool(v)
  63. case int32:
  64. return ValueOfInt32(v)
  65. case int64:
  66. return ValueOfInt64(v)
  67. case uint32:
  68. return ValueOfUint32(v)
  69. case uint64:
  70. return ValueOfUint64(v)
  71. case float32:
  72. return ValueOfFloat32(v)
  73. case float64:
  74. return ValueOfFloat64(v)
  75. case string:
  76. return ValueOfString(v)
  77. case []byte:
  78. return ValueOfBytes(v)
  79. case EnumNumber:
  80. return ValueOfEnum(v)
  81. case Message, List, Map:
  82. return valueOfIface(v)
  83. case ProtoMessage:
  84. panic(fmt.Sprintf("invalid proto.Message(%T) type, expected a protoreflect.Message type", v))
  85. default:
  86. panic(fmt.Sprintf("invalid type: %T", v))
  87. }
  88. }
  89. // ValueOfBool returns a new boolean value.
  90. func ValueOfBool(v bool) Value {
  91. if v {
  92. return Value{typ: boolType, num: 1}
  93. } else {
  94. return Value{typ: boolType, num: 0}
  95. }
  96. }
  97. // ValueOfInt32 returns a new int32 value.
  98. func ValueOfInt32(v int32) Value {
  99. return Value{typ: int32Type, num: uint64(v)}
  100. }
  101. // ValueOfInt64 returns a new int64 value.
  102. func ValueOfInt64(v int64) Value {
  103. return Value{typ: int64Type, num: uint64(v)}
  104. }
  105. // ValueOfUint32 returns a new uint32 value.
  106. func ValueOfUint32(v uint32) Value {
  107. return Value{typ: uint32Type, num: uint64(v)}
  108. }
  109. // ValueOfUint64 returns a new uint64 value.
  110. func ValueOfUint64(v uint64) Value {
  111. return Value{typ: uint64Type, num: v}
  112. }
  113. // ValueOfFloat32 returns a new float32 value.
  114. func ValueOfFloat32(v float32) Value {
  115. return Value{typ: float32Type, num: uint64(math.Float64bits(float64(v)))}
  116. }
  117. // ValueOfFloat64 returns a new float64 value.
  118. func ValueOfFloat64(v float64) Value {
  119. return Value{typ: float64Type, num: uint64(math.Float64bits(float64(v)))}
  120. }
  121. // ValueOfString returns a new string value.
  122. func ValueOfString(v string) Value {
  123. return valueOfString(v)
  124. }
  125. // ValueOfBytes returns a new bytes value.
  126. func ValueOfBytes(v []byte) Value {
  127. return valueOfBytes(v[:len(v):len(v)])
  128. }
  129. // ValueOfEnum returns a new enum value.
  130. func ValueOfEnum(v EnumNumber) Value {
  131. return Value{typ: enumType, num: uint64(v)}
  132. }
  133. // ValueOfMessage returns a new Message value.
  134. func ValueOfMessage(v Message) Value {
  135. return valueOfIface(v)
  136. }
  137. // ValueOfList returns a new List value.
  138. func ValueOfList(v List) Value {
  139. return valueOfIface(v)
  140. }
  141. // ValueOfMap returns a new Map value.
  142. func ValueOfMap(v Map) Value {
  143. return valueOfIface(v)
  144. }
  145. // IsValid reports whether v is populated with a value.
  146. func (v Value) IsValid() bool {
  147. return v.typ != nilType
  148. }
  149. // Interface returns v as an interface{}.
  150. //
  151. // Invariant: v == ValueOf(v).Interface()
  152. func (v Value) Interface() interface{} {
  153. switch v.typ {
  154. case nilType:
  155. return nil
  156. case boolType:
  157. return v.Bool()
  158. case int32Type:
  159. return int32(v.Int())
  160. case int64Type:
  161. return int64(v.Int())
  162. case uint32Type:
  163. return uint32(v.Uint())
  164. case uint64Type:
  165. return uint64(v.Uint())
  166. case float32Type:
  167. return float32(v.Float())
  168. case float64Type:
  169. return float64(v.Float())
  170. case stringType:
  171. return v.String()
  172. case bytesType:
  173. return v.Bytes()
  174. case enumType:
  175. return v.Enum()
  176. default:
  177. return v.getIface()
  178. }
  179. }
  180. func (v Value) typeName() string {
  181. switch v.typ {
  182. case nilType:
  183. return "nil"
  184. case boolType:
  185. return "bool"
  186. case int32Type:
  187. return "int32"
  188. case int64Type:
  189. return "int64"
  190. case uint32Type:
  191. return "uint32"
  192. case uint64Type:
  193. return "uint64"
  194. case float32Type:
  195. return "float32"
  196. case float64Type:
  197. return "float64"
  198. case stringType:
  199. return "string"
  200. case bytesType:
  201. return "bytes"
  202. case enumType:
  203. return "enum"
  204. default:
  205. switch v := v.getIface().(type) {
  206. case Message:
  207. return "message"
  208. case List:
  209. return "list"
  210. case Map:
  211. return "map"
  212. default:
  213. return fmt.Sprintf("<unknown: %T>", v)
  214. }
  215. }
  216. }
  217. func (v Value) panicMessage(what string) string {
  218. return fmt.Sprintf("type mismatch: cannot convert %v to %s", v.typeName(), what)
  219. }
  220. // Bool returns v as a bool and panics if the type is not a bool.
  221. func (v Value) Bool() bool {
  222. switch v.typ {
  223. case boolType:
  224. return v.num > 0
  225. default:
  226. panic(v.panicMessage("bool"))
  227. }
  228. }
  229. // Int returns v as a int64 and panics if the type is not a int32 or int64.
  230. func (v Value) Int() int64 {
  231. switch v.typ {
  232. case int32Type, int64Type:
  233. return int64(v.num)
  234. default:
  235. panic(v.panicMessage("int"))
  236. }
  237. }
  238. // Uint returns v as a uint64 and panics if the type is not a uint32 or uint64.
  239. func (v Value) Uint() uint64 {
  240. switch v.typ {
  241. case uint32Type, uint64Type:
  242. return uint64(v.num)
  243. default:
  244. panic(v.panicMessage("uint"))
  245. }
  246. }
  247. // Float returns v as a float64 and panics if the type is not a float32 or float64.
  248. func (v Value) Float() float64 {
  249. switch v.typ {
  250. case float32Type, float64Type:
  251. return math.Float64frombits(uint64(v.num))
  252. default:
  253. panic(v.panicMessage("float"))
  254. }
  255. }
  256. // String returns v as a string. Since this method implements fmt.Stringer,
  257. // this returns the formatted string value for any non-string type.
  258. func (v Value) String() string {
  259. switch v.typ {
  260. case stringType:
  261. return v.getString()
  262. default:
  263. return fmt.Sprint(v.Interface())
  264. }
  265. }
  266. // Bytes returns v as a []byte and panics if the type is not a []byte.
  267. func (v Value) Bytes() []byte {
  268. switch v.typ {
  269. case bytesType:
  270. return v.getBytes()
  271. default:
  272. panic(v.panicMessage("bytes"))
  273. }
  274. }
  275. // Enum returns v as a EnumNumber and panics if the type is not a EnumNumber.
  276. func (v Value) Enum() EnumNumber {
  277. switch v.typ {
  278. case enumType:
  279. return EnumNumber(v.num)
  280. default:
  281. panic(v.panicMessage("enum"))
  282. }
  283. }
  284. // Message returns v as a Message and panics if the type is not a Message.
  285. func (v Value) Message() Message {
  286. switch vi := v.getIface().(type) {
  287. case Message:
  288. return vi
  289. default:
  290. panic(v.panicMessage("message"))
  291. }
  292. }
  293. // List returns v as a List and panics if the type is not a List.
  294. func (v Value) List() List {
  295. switch vi := v.getIface().(type) {
  296. case List:
  297. return vi
  298. default:
  299. panic(v.panicMessage("list"))
  300. }
  301. }
  302. // Map returns v as a Map and panics if the type is not a Map.
  303. func (v Value) Map() Map {
  304. switch vi := v.getIface().(type) {
  305. case Map:
  306. return vi
  307. default:
  308. panic(v.panicMessage("map"))
  309. }
  310. }
  311. // MapKey returns v as a MapKey and panics for invalid MapKey types.
  312. func (v Value) MapKey() MapKey {
  313. switch v.typ {
  314. case boolType, int32Type, int64Type, uint32Type, uint64Type, stringType:
  315. return MapKey(v)
  316. default:
  317. panic(v.panicMessage("map key"))
  318. }
  319. }
  320. // MapKey is used to index maps, where the Go type of the MapKey must match
  321. // the specified key Kind (see MessageDescriptor.IsMapEntry).
  322. // The following shows what Go type is used to represent each proto Kind:
  323. //
  324. // ╔═════════╤═════════════════════════════════════╗
  325. // ║ Go type │ Protobuf kind ║
  326. // ╠═════════╪═════════════════════════════════════╣
  327. // ║ bool │ BoolKind ║
  328. // ║ int32 │ Int32Kind, Sint32Kind, Sfixed32Kind ║
  329. // ║ int64 │ Int64Kind, Sint64Kind, Sfixed64Kind ║
  330. // ║ uint32 │ Uint32Kind, Fixed32Kind ║
  331. // ║ uint64 │ Uint64Kind, Fixed64Kind ║
  332. // ║ string │ StringKind ║
  333. // ╚═════════╧═════════════════════════════════════╝
  334. //
  335. // A MapKey is constructed and accessed through a Value:
  336. // k := ValueOf("hash").MapKey() // convert string to MapKey
  337. // s := k.String() // convert MapKey to string
  338. //
  339. // The MapKey is a strict subset of valid types used in Value;
  340. // converting a Value to a MapKey with an invalid type panics.
  341. type MapKey value
  342. // IsValid reports whether k is populated with a value.
  343. func (k MapKey) IsValid() bool {
  344. return Value(k).IsValid()
  345. }
  346. // Interface returns k as an interface{}.
  347. func (k MapKey) Interface() interface{} {
  348. return Value(k).Interface()
  349. }
  350. // Bool returns k as a bool and panics if the type is not a bool.
  351. func (k MapKey) Bool() bool {
  352. return Value(k).Bool()
  353. }
  354. // Int returns k as a int64 and panics if the type is not a int32 or int64.
  355. func (k MapKey) Int() int64 {
  356. return Value(k).Int()
  357. }
  358. // Uint returns k as a uint64 and panics if the type is not a uint32 or uint64.
  359. func (k MapKey) Uint() uint64 {
  360. return Value(k).Uint()
  361. }
  362. // String returns k as a string. Since this method implements fmt.Stringer,
  363. // this returns the formatted string value for any non-string type.
  364. func (k MapKey) String() string {
  365. return Value(k).String()
  366. }
  367. // Value returns k as a Value.
  368. func (k MapKey) Value() Value {
  369. return Value(k)
  370. }