1 // Copyright 2013 The Flutter Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_ 6 #define FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_ 7 8 #include <assert.h> 9 #include <cstdint> 10 #include <map> 11 #include <string> 12 #include <utility> 13 #include <vector> 14 15 namespace flutter { 16 17 static_assert(sizeof(double) == 8, "EncodableValue requires a 64-bit double"); 18 19 class EncodableValue; 20 // Convenience type aliases for list and map EncodableValue types. 21 using EncodableList = std::vector<EncodableValue>; 22 using EncodableMap = std::map<EncodableValue, EncodableValue>; 23 24 // An object that can contain any value or collection type supported by 25 // Flutter's standard method codec. 26 // 27 // For details, see: 28 // https://api.flutter.dev/flutter/services/StandardMessageCodec-class.html 29 // 30 // As an example, the following Dart structure: 31 // { 32 // 'flag': true, 33 // 'name': 'Thing', 34 // 'values': [1, 2.0, 4], 35 // } 36 // would correspond to: 37 // EncodableValue(EncodableMap{ 38 // {EncodableValue("flag"), EncodableValue(true)}, 39 // {EncodableValue("name"), EncodableValue("Thing")}, 40 // {EncodableValue("values"), EncodableValue(EncodableList{ 41 // EncodableValue(1), 42 // EncodableValue(2.0), 43 // EncodableValue(4), 44 // })}, 45 // }) 46 class EncodableValue { 47 public: 48 // Possible types for an EncodableValue to reperesent. 49 enum class Type { 50 kNull, // A null value. 51 kBool, // A boolean value. 52 kInt, // A 32-bit integer. 53 kLong, // A 64-bit integer. 54 kDouble, // A 64-bit floating point number. 55 kString, // A string. 56 kByteList, // A list of bytes. 57 kIntList, // A list of 32-bit integers. 58 kLongList, // A list of 64-bit integers. 59 kDoubleList, // A list of 64-bit floating point numbers. 60 kList, // A list of EncodableValues. 61 kMap, // A mapping from EncodableValues to EncodableValues. 62 }; 63 64 // Creates an instance representing a null value. EncodableValue()65 EncodableValue() {} 66 67 // Creates an instance representing a bool value. EncodableValue(bool value)68 explicit EncodableValue(bool value) : bool_(value), type_(Type::kBool) {} 69 70 // Creates an instance representing a 32-bit integer value. EncodableValue(int32_t value)71 explicit EncodableValue(int32_t value) : int_(value), type_(Type::kInt) {} 72 73 // Creates an instance representing a 64-bit integer value. EncodableValue(int64_t value)74 explicit EncodableValue(int64_t value) : long_(value), type_(Type::kLong) {} 75 76 // Creates an instance representing a 64-bit floating point value. EncodableValue(double value)77 explicit EncodableValue(double value) 78 : double_(value), type_(Type::kDouble) {} 79 80 // Creates an instance representing a string value. EncodableValue(const char * value)81 explicit EncodableValue(const char* value) 82 : string_(new std::string(value)), type_(Type::kString) {} 83 84 // Creates an instance representing a string value. EncodableValue(const std::string & value)85 explicit EncodableValue(const std::string& value) 86 : string_(new std::string(value)), type_(Type::kString) {} 87 88 // Creates an instance representing a list of bytes. EncodableValue(std::vector<uint8_t> list)89 explicit EncodableValue(std::vector<uint8_t> list) 90 : byte_list_(new std::vector<uint8_t>(std::move(list))), 91 type_(Type::kByteList) {} 92 93 // Creates an instance representing a list of 32-bit integers. EncodableValue(std::vector<int32_t> list)94 explicit EncodableValue(std::vector<int32_t> list) 95 : int_list_(new std::vector<int32_t>(std::move(list))), 96 type_(Type::kIntList) {} 97 98 // Creates an instance representing a list of 64-bit integers. EncodableValue(std::vector<int64_t> list)99 explicit EncodableValue(std::vector<int64_t> list) 100 : long_list_(new std::vector<int64_t>(std::move(list))), 101 type_(Type::kLongList) {} 102 103 // Creates an instance representing a list of 64-bit floating point values. EncodableValue(std::vector<double> list)104 explicit EncodableValue(std::vector<double> list) 105 : double_list_(new std::vector<double>(std::move(list))), 106 type_(Type::kDoubleList) {} 107 108 // Creates an instance representing a list of EncodableValues. EncodableValue(EncodableList list)109 explicit EncodableValue(EncodableList list) 110 : list_(new EncodableList(std::move(list))), type_(Type::kList) {} 111 112 // Creates an instance representing a map from EncodableValues to 113 // EncodableValues. EncodableValue(EncodableMap map)114 explicit EncodableValue(EncodableMap map) 115 : map_(new EncodableMap(std::move(map))), type_(Type::kMap) {} 116 117 // Convience constructor for creating default value of the given type. 118 // 119 // Collections types will be empty, numeric types will be 0, strings will be 120 // empty, and booleans will be false. For non-collection types, prefer using 121 // the value-based constructor with an explicit value for clarity. EncodableValue(Type type)122 explicit EncodableValue(Type type) : type_(type) { 123 switch (type_) { 124 case Type::kNull: 125 break; 126 case Type::kBool: 127 bool_ = false; 128 break; 129 case Type::kInt: 130 int_ = 0; 131 break; 132 case Type::kLong: 133 long_ = 0; 134 break; 135 case Type::kDouble: 136 double_ = 0.0; 137 break; 138 case Type::kString: 139 string_ = new std::string(); 140 break; 141 case Type::kByteList: 142 byte_list_ = new std::vector<uint8_t>(); 143 break; 144 case Type::kIntList: 145 int_list_ = new std::vector<int32_t>(); 146 break; 147 case Type::kLongList: 148 long_list_ = new std::vector<int64_t>(); 149 break; 150 case Type::kDoubleList: 151 double_list_ = new std::vector<double>(); 152 break; 153 case Type::kList: 154 list_ = new std::vector<EncodableValue>(); 155 break; 156 case Type::kMap: 157 map_ = new std::map<EncodableValue, EncodableValue>(); 158 break; 159 } 160 } 161 ~EncodableValue()162 ~EncodableValue() { DestroyValue(); } 163 EncodableValue(const EncodableValue & other)164 EncodableValue(const EncodableValue& other) { 165 DestroyValue(); 166 167 type_ = other.type_; 168 switch (type_) { 169 case Type::kNull: 170 break; 171 case Type::kBool: 172 bool_ = other.bool_; 173 break; 174 case Type::kInt: 175 int_ = other.int_; 176 break; 177 case Type::kLong: 178 long_ = other.long_; 179 break; 180 case Type::kDouble: 181 double_ = other.double_; 182 break; 183 case Type::kString: 184 string_ = new std::string(*other.string_); 185 break; 186 case Type::kByteList: 187 byte_list_ = new std::vector<uint8_t>(*other.byte_list_); 188 break; 189 case Type::kIntList: 190 int_list_ = new std::vector<int32_t>(*other.int_list_); 191 break; 192 case Type::kLongList: 193 long_list_ = new std::vector<int64_t>(*other.long_list_); 194 break; 195 case Type::kDoubleList: 196 double_list_ = new std::vector<double>(*other.double_list_); 197 break; 198 case Type::kList: 199 list_ = new std::vector<EncodableValue>(*other.list_); 200 break; 201 case Type::kMap: 202 map_ = new std::map<EncodableValue, EncodableValue>(*other.map_); 203 break; 204 } 205 } 206 EncodableValue(EncodableValue && other)207 EncodableValue(EncodableValue&& other) { *this = std::move(other); } 208 209 EncodableValue& operator=(const EncodableValue& other) { 210 if (&other == this) { 211 return *this; 212 } 213 using std::swap; 214 EncodableValue temp(other); 215 swap(*this, temp); 216 return *this; 217 } 218 219 EncodableValue& operator=(EncodableValue&& other) { 220 if (&other == this) { 221 return *this; 222 } 223 DestroyValue(); 224 225 type_ = other.type_; 226 switch (type_) { 227 case Type::kNull: 228 break; 229 case Type::kBool: 230 bool_ = other.bool_; 231 break; 232 case Type::kInt: 233 int_ = other.int_; 234 break; 235 case Type::kLong: 236 long_ = other.long_; 237 break; 238 case Type::kDouble: 239 double_ = other.double_; 240 break; 241 case Type::kString: 242 string_ = other.string_; 243 break; 244 case Type::kByteList: 245 byte_list_ = other.byte_list_; 246 break; 247 case Type::kIntList: 248 int_list_ = other.int_list_; 249 break; 250 case Type::kLongList: 251 long_list_ = other.long_list_; 252 break; 253 case Type::kDoubleList: 254 double_list_ = other.double_list_; 255 break; 256 case Type::kList: 257 list_ = other.list_; 258 break; 259 case Type::kMap: 260 map_ = other.map_; 261 break; 262 } 263 // Ensure that destruction doesn't run on the source of the move. 264 other.type_ = Type::kNull; 265 return *this; 266 } 267 268 // Allow assigning any value type that can be used for a constructor. 269 template <typename T> 270 EncodableValue& operator=(const T& value) { 271 *this = EncodableValue(value); 272 return *this; 273 } 274 275 // This operator exists only to provide a stable ordering for use as a 276 // std::map key. It does not attempt to provide useful ordering semantics. 277 // Notably: 278 // - Numeric values are not guaranteed any ordering across numeric types. 279 // E.g., 1 as a Long may sort after 100 as an Int. 280 // - Collection types use pointer equality, rather than value. This means that 281 // multiple collections with the same values will end up as separate keys 282 // in a map (consistent with default Dart Map behavior). 283 bool operator<(const EncodableValue& other) const { 284 if (type_ != other.type_) { 285 return type_ < other.type_; 286 } 287 switch (type_) { 288 case Type::kNull: 289 return false; 290 case Type::kBool: 291 return bool_ < other.bool_; 292 case Type::kInt: 293 return int_ < other.int_; 294 case Type::kLong: 295 return long_ < other.long_; 296 case Type::kDouble: 297 return double_ < other.double_; 298 case Type::kString: 299 return *string_ < *other.string_; 300 case Type::kByteList: 301 case Type::kIntList: 302 case Type::kLongList: 303 case Type::kDoubleList: 304 case Type::kList: 305 case Type::kMap: 306 return this < &other; 307 } 308 assert(false); 309 return false; 310 } 311 312 // Returns the bool value this object represents. 313 // 314 // It is a programming error to call this unless IsBool() is true. BoolValue()315 bool BoolValue() const { 316 assert(IsBool()); 317 return bool_; 318 } 319 320 // Returns the 32-bit integer value this object represents. 321 // 322 // It is a programming error to call this unless IsInt() is true. IntValue()323 int32_t IntValue() const { 324 assert(IsInt()); 325 return int_; 326 } 327 328 // Returns the 64-bit integer value this object represents. 329 // 330 // It is a programming error to call this unless IsLong() or IsInt() is true. 331 // 332 // Note that calling this function on an Int value is the only case where 333 // a *Value() function can be called without the corresponding Is*() being 334 // true. This is to simplify handling objects received from Flutter where the 335 // values may be larger than 32-bit, since they have the same type on the Dart 336 // side, but will be either 32-bit or 64-bit here depending on the value. LongValue()337 int64_t LongValue() const { 338 assert(IsLong() || IsInt()); 339 if (IsLong()) { 340 return long_; 341 } 342 return int_; 343 } 344 345 // Returns the double value this object represents. 346 // 347 // It is a programming error to call this unless IsDouble() is true. DoubleValue()348 double DoubleValue() const { 349 assert(IsDouble()); 350 return double_; 351 } 352 353 // Returns the string value this object represents. 354 // 355 // It is a programming error to call this unless IsString() is true. StringValue()356 const std::string& StringValue() const { 357 assert(IsString()); 358 return *string_; 359 } 360 361 // Returns the byte list this object represents. 362 // 363 // It is a programming error to call this unless IsByteList() is true. ByteListValue()364 const std::vector<uint8_t>& ByteListValue() const { 365 assert(IsByteList()); 366 return *byte_list_; 367 } 368 369 // Returns the byte list this object represents. 370 // 371 // It is a programming error to call this unless IsByteList() is true. ByteListValue()372 std::vector<uint8_t>& ByteListValue() { 373 assert(IsByteList()); 374 return *byte_list_; 375 } 376 377 // Returns the 32-bit integer list this object represents. 378 // 379 // It is a programming error to call this unless IsIntList() is true. IntListValue()380 const std::vector<int32_t>& IntListValue() const { 381 assert(IsIntList()); 382 return *int_list_; 383 } 384 385 // Returns the 32-bit integer list this object represents. 386 // 387 // It is a programming error to call this unless IsIntList() is true. IntListValue()388 std::vector<int32_t>& IntListValue() { 389 assert(IsIntList()); 390 return *int_list_; 391 } 392 393 // Returns the 64-bit integer list this object represents. 394 // 395 // It is a programming error to call this unless IsLongList() is true. LongListValue()396 const std::vector<int64_t>& LongListValue() const { 397 assert(IsLongList()); 398 return *long_list_; 399 } 400 401 // Returns the 64-bit integer list this object represents. 402 // 403 // It is a programming error to call this unless IsLongList() is true. LongListValue()404 std::vector<int64_t>& LongListValue() { 405 assert(IsLongList()); 406 return *long_list_; 407 } 408 409 // Returns the double list this object represents. 410 // 411 // It is a programming error to call this unless IsDoubleList() is true. DoubleListValue()412 const std::vector<double>& DoubleListValue() const { 413 assert(IsDoubleList()); 414 return *double_list_; 415 } 416 417 // Returns the double list this object represents. 418 // 419 // It is a programming error to call this unless IsDoubleList() is true. DoubleListValue()420 std::vector<double>& DoubleListValue() { 421 assert(IsDoubleList()); 422 return *double_list_; 423 } 424 425 // Returns the list of EncodableValues this object represents. 426 // 427 // It is a programming error to call this unless IsList() is true. ListValue()428 const EncodableList& ListValue() const { 429 assert(IsList()); 430 return *list_; 431 } 432 433 // Returns the list of EncodableValues this object represents. 434 // 435 // It is a programming error to call this unless IsList() is true. ListValue()436 EncodableList& ListValue() { 437 assert(IsList()); 438 return *list_; 439 } 440 441 // Returns the map of EncodableValue : EncodableValue pairs this object 442 // represent. 443 // 444 // It is a programming error to call this unless IsMap() is true. MapValue()445 const EncodableMap& MapValue() const { 446 assert(IsMap()); 447 return *map_; 448 } 449 450 // Returns the map of EncodableValue : EncodableValue pairs this object 451 // represent. 452 // 453 // It is a programming error to call this unless IsMap() is true. MapValue()454 EncodableMap& MapValue() { 455 assert(IsMap()); 456 return *map_; 457 } 458 459 // Returns true if this represents a null value. IsNull()460 bool IsNull() const { return type_ == Type::kNull; } 461 462 // Returns true if this represents a bool value. IsBool()463 bool IsBool() const { return type_ == Type::kBool; } 464 465 // Returns true if this represents a 32-bit integer value. IsInt()466 bool IsInt() const { return type_ == Type::kInt; } 467 468 // Returns true if this represents a 64-bit integer value. IsLong()469 bool IsLong() const { return type_ == Type::kLong; } 470 471 // Returns true if this represents a double value. IsDouble()472 bool IsDouble() const { return type_ == Type::kDouble; } 473 474 // Returns true if this represents a string value. IsString()475 bool IsString() const { return type_ == Type::kString; } 476 477 // Returns true if this represents a list of bytes. IsByteList()478 bool IsByteList() const { return type_ == Type::kByteList; } 479 480 // Returns true if this represents a list of 32-bit integers. IsIntList()481 bool IsIntList() const { return type_ == Type::kIntList; } 482 483 // Returns true if this represents a list of 64-bit integers. IsLongList()484 bool IsLongList() const { return type_ == Type::kLongList; } 485 486 // Returns true if this represents a list of doubles. IsDoubleList()487 bool IsDoubleList() const { return type_ == Type::kDoubleList; } 488 489 // Returns true if this represents a list of EncodableValues. IsList()490 bool IsList() const { return type_ == Type::kList; } 491 492 // Returns true if this represents a map of EncodableValue : EncodableValue 493 // pairs. IsMap()494 bool IsMap() const { return type_ == Type::kMap; } 495 496 // Returns the type this value represents. 497 // 498 // This is primarily intended for use with switch(); for individual checks, 499 // prefer an Is*() call. type()500 Type type() const { return type_; } 501 502 private: 503 // Performs any cleanup necessary for the active union value. This must be 504 // called before assigning a new value, and on object destruction. 505 // 506 // After calling this, type_ will alway be kNull. DestroyValue()507 void DestroyValue() { 508 switch (type_) { 509 case Type::kNull: 510 case Type::kBool: 511 case Type::kInt: 512 case Type::kLong: 513 case Type::kDouble: 514 break; 515 case Type::kString: 516 delete string_; 517 break; 518 case Type::kByteList: 519 delete byte_list_; 520 break; 521 case Type::kIntList: 522 delete int_list_; 523 break; 524 case Type::kLongList: 525 delete long_list_; 526 break; 527 case Type::kDoubleList: 528 delete double_list_; 529 break; 530 case Type::kList: 531 delete list_; 532 break; 533 case Type::kMap: 534 delete map_; 535 break; 536 } 537 538 type_ = Type::kNull; 539 } 540 541 // The anonymous union that stores the represented value. Accessing any of 542 // these entries other than the one that corresponds to the current value of 543 // |type_| has undefined behavior. 544 // 545 // Pointers are used for the non-POD types to avoid making the overall size 546 // of the union unnecessarily large. 547 // 548 // TODO: Replace this with std::variant once c++17 is available. 549 union { 550 bool bool_; 551 int32_t int_; 552 int64_t long_; 553 double double_; 554 std::string* string_; 555 std::vector<uint8_t>* byte_list_; 556 std::vector<int32_t>* int_list_; 557 std::vector<int64_t>* long_list_; 558 std::vector<double>* double_list_; 559 std::vector<EncodableValue>* list_; 560 std::map<EncodableValue, EncodableValue>* map_; 561 }; 562 563 // The currently active union entry. 564 Type type_ = Type::kNull; 565 }; 566 567 } // namespace flutter 568 569 #endif // FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_ 570