value_union.go 13 KB

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