未验证 提交 b819b62b 编写于 作者: S stuartmorgan 提交者: GitHub

Variant type for C++ client wrapper (#8592)

Adds a type that can hold any of the types corresponding to the Dart types
that are supported by the standard message channel codec. This provides
the foundation for adding standard message codec support for the C++
desktop shells (flutter/flutter#30670).
上级 db36d28e
......@@ -560,9 +560,11 @@ FILE: ../../../flutter/shell/platform/android/platform_view_android_jni.cc
FILE: ../../../flutter/shell/platform/android/platform_view_android_jni.h
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc
FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/encodable_value_unittests.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/engine_method_result.cc
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/basic_message_channel.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/encodable_value.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/engine_method_result.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/json_message_codec.h
FILE: ../../../flutter/shell/platform/common/cpp/client_wrapper/include/flutter/json_method_codec.h
......
......@@ -7,6 +7,7 @@ import("publish.gni")
_wrapper_includes = [
"include/flutter/basic_message_channel.h",
"include/flutter/binary_messenger.h",
"include/flutter/encodable_value.h",
"include/flutter/engine_method_result.h",
"include/flutter/json_message_codec.h",
"include/flutter/json_method_codec.h",
......@@ -72,6 +73,7 @@ executable("client_wrapper_unittests") {
# TODO: Add more unit tests.
sources = [
"encodable_value_unittests.cc",
"method_call_unittests.cc",
"plugin_registrar_unittests.cc",
]
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/encodable_value.h"
#include <limits>
#include "gtest/gtest.h"
namespace flutter {
// Verifies that value.type() is |type|, and that of all the Is* methods, only
// the one that matches the type is true.
void VerifyType(EncodableValue& value,
EncodableValue::EncodableValue::Type type) {
EXPECT_EQ(value.type(), type);
EXPECT_EQ(value.IsNull(), type == EncodableValue::Type::kNull);
EXPECT_EQ(value.IsBool(), type == EncodableValue::Type::kBool);
EXPECT_EQ(value.IsInt(), type == EncodableValue::Type::kInt);
EXPECT_EQ(value.IsLong(), type == EncodableValue::Type::kLong);
EXPECT_EQ(value.IsDouble(), type == EncodableValue::Type::kDouble);
EXPECT_EQ(value.IsString(), type == EncodableValue::Type::kString);
EXPECT_EQ(value.IsByteList(), type == EncodableValue::Type::kByteList);
EXPECT_EQ(value.IsIntList(), type == EncodableValue::Type::kIntList);
EXPECT_EQ(value.IsLongList(), type == EncodableValue::Type::kLongList);
EXPECT_EQ(value.IsDoubleList(), type == EncodableValue::Type::kDoubleList);
EXPECT_EQ(value.IsList(), type == EncodableValue::Type::kList);
EXPECT_EQ(value.IsMap(), type == EncodableValue::Type::kMap);
}
TEST(EncodableValueTest, Null) {
EncodableValue value;
VerifyType(value, EncodableValue::Type::kNull);
}
TEST(EncodableValueTest, Bool) {
EncodableValue value(false);
VerifyType(value, EncodableValue::Type::kBool);
EXPECT_FALSE(value.BoolValue());
value = true;
EXPECT_TRUE(value.BoolValue());
}
TEST(EncodableValueTest, Int) {
EncodableValue value(42);
VerifyType(value, EncodableValue::Type::kInt);
EXPECT_EQ(value.IntValue(), 42);
value = std::numeric_limits<int32_t>::max();
EXPECT_EQ(value.IntValue(), std::numeric_limits<int32_t>::max());
}
TEST(EncodableValueTest, LongValueFromInt) {
EncodableValue value(std::numeric_limits<int32_t>::max());
EXPECT_EQ(value.LongValue(), std::numeric_limits<int32_t>::max());
}
TEST(EncodableValueTest, Long) {
EncodableValue value(42l);
VerifyType(value, EncodableValue::Type::kLong);
EXPECT_EQ(value.LongValue(), 42);
value = std::numeric_limits<int64_t>::max();
EXPECT_EQ(value.LongValue(), std::numeric_limits<int64_t>::max());
}
TEST(EncodableValueTest, Double) {
EncodableValue value(3.14);
VerifyType(value, EncodableValue::Type::kDouble);
EXPECT_EQ(value.DoubleValue(), 3.14);
value = std::numeric_limits<double>::max();
EXPECT_EQ(value.DoubleValue(), std::numeric_limits<double>::max());
}
TEST(EncodableValueTest, String) {
std::string hello("Hello, world!");
EncodableValue value(hello);
VerifyType(value, EncodableValue::Type::kString);
EXPECT_EQ(value.StringValue(), hello);
value = "Goodbye";
EXPECT_EQ(value.StringValue(), "Goodbye");
}
TEST(EncodableValueTest, UInt8List) {
std::vector<uint8_t> data = {0, 2};
EncodableValue value(data);
VerifyType(value, EncodableValue::Type::kByteList);
std::vector<uint8_t>& list_value = value.ByteListValue();
list_value.push_back(std::numeric_limits<uint8_t>::max());
EXPECT_EQ(list_value[0], 0);
EXPECT_EQ(list_value[1], 2);
ASSERT_EQ(list_value.size(), 3u);
EXPECT_EQ(data.size(), 2u);
EXPECT_EQ(list_value[2], std::numeric_limits<uint8_t>::max());
}
TEST(EncodableValueTest, Int32List) {
std::vector<int32_t> data = {-10, 2};
EncodableValue value(data);
VerifyType(value, EncodableValue::Type::kIntList);
std::vector<int32_t>& list_value = value.IntListValue();
list_value.push_back(std::numeric_limits<int32_t>::max());
EXPECT_EQ(list_value[0], -10);
EXPECT_EQ(list_value[1], 2);
ASSERT_EQ(list_value.size(), 3u);
EXPECT_EQ(data.size(), 2u);
EXPECT_EQ(list_value[2], std::numeric_limits<int32_t>::max());
}
TEST(EncodableValueTest, Int64List) {
std::vector<int64_t> data = {-10, 2};
EncodableValue value(data);
VerifyType(value, EncodableValue::Type::kLongList);
std::vector<int64_t>& list_value = value.LongListValue();
list_value.push_back(std::numeric_limits<int64_t>::max());
EXPECT_EQ(list_value[0], -10);
EXPECT_EQ(list_value[1], 2);
ASSERT_EQ(list_value.size(), 3u);
EXPECT_EQ(data.size(), 2u);
EXPECT_EQ(list_value[2], std::numeric_limits<int64_t>::max());
}
TEST(EncodableValueTest, DoubleList) {
std::vector<double> data = {-10.0, 2.0};
EncodableValue value(data);
VerifyType(value, EncodableValue::Type::kDoubleList);
std::vector<double>& list_value = value.DoubleListValue();
list_value.push_back(std::numeric_limits<double>::max());
EXPECT_EQ(list_value[0], -10.0);
EXPECT_EQ(list_value[1], 2.0);
ASSERT_EQ(list_value.size(), 3u);
EXPECT_EQ(data.size(), 2u);
EXPECT_EQ(list_value[2], std::numeric_limits<double>::max());
}
TEST(EncodableValueTest, List) {
EncodableList encodables = {
EncodableValue(1),
EncodableValue(2.0),
EncodableValue("Three"),
};
EncodableValue value(encodables);
VerifyType(value, EncodableValue::Type::kList);
EncodableList& list_value = value.ListValue();
EXPECT_EQ(list_value[0].IntValue(), 1);
EXPECT_EQ(list_value[1].DoubleValue(), 2.0);
EXPECT_EQ(list_value[2].StringValue(), "Three");
// Ensure that it's a modifiable copy of the original array.
list_value.push_back(EncodableValue(true));
ASSERT_EQ(list_value.size(), 4u);
EXPECT_EQ(encodables.size(), 3u);
EXPECT_EQ(value.ListValue()[3].BoolValue(), true);
}
TEST(EncodableValueTest, Map) {
EncodableMap encodables = {
{EncodableValue(), EncodableValue(std::vector<int32_t>{1, 2, 3})},
{EncodableValue(1), EncodableValue(10000l)},
{EncodableValue("two"), EncodableValue(7)},
};
EncodableValue value(encodables);
VerifyType(value, EncodableValue::Type::kMap);
EncodableMap& map_value = value.MapValue();
EXPECT_EQ(map_value[EncodableValue()].IsIntList(), true);
EXPECT_EQ(map_value[EncodableValue(1)].LongValue(), 10000l);
EXPECT_EQ(map_value[EncodableValue("two")].IntValue(), 7);
// Ensure that it's a modifiable copy of the original map.
map_value[EncodableValue(true)] = EncodableValue(false);
ASSERT_EQ(map_value.size(), 4u);
EXPECT_EQ(encodables.size(), 3u);
EXPECT_EQ(map_value[EncodableValue(true)].BoolValue(), false);
}
TEST(EncodableValueTest, EmptyTypeConstructor) {
EXPECT_TRUE(EncodableValue(EncodableValue::Type::kNull).IsNull());
EXPECT_EQ(EncodableValue(EncodableValue::Type::kBool).BoolValue(), false);
EXPECT_EQ(EncodableValue(EncodableValue::Type::kInt).IntValue(), 0);
EXPECT_EQ(EncodableValue(EncodableValue::Type::kLong).LongValue(), 0l);
EXPECT_EQ(EncodableValue(EncodableValue::Type::kDouble).DoubleValue(), 0.0);
EXPECT_EQ(EncodableValue(EncodableValue::Type::kString).StringValue().size(),
0u);
EXPECT_EQ(
EncodableValue(EncodableValue::Type::kByteList).ByteListValue().size(),
0u);
EXPECT_EQ(
EncodableValue(EncodableValue::Type::kIntList).IntListValue().size(), 0u);
EXPECT_EQ(
EncodableValue(EncodableValue::Type::kLongList).LongListValue().size(),
0u);
EXPECT_EQ(EncodableValue(EncodableValue::Type::kDoubleList)
.DoubleListValue()
.size(),
0u);
EXPECT_EQ(EncodableValue(EncodableValue::Type::kList).ListValue().size(), 0u);
EXPECT_EQ(EncodableValue(EncodableValue::Type::kMap).MapValue().size(), 0u);
}
// Tests that the < operator meets the requirements of using EncodableValue as
// a map key.
TEST(EncodableValueTest, Comparison) {
EncodableList values = {
// Null
EncodableValue(),
// Bool
EncodableValue(true),
EncodableValue(false),
// Int
EncodableValue(-7),
EncodableValue(0),
EncodableValue(100),
// Long
EncodableValue(-7l),
EncodableValue(0l),
EncodableValue(100l),
// Double
EncodableValue(-7.0),
EncodableValue(0.0),
EncodableValue(100.0),
// String
EncodableValue("one"),
EncodableValue("two"),
// ByteList
EncodableValue(std::vector<uint8_t>{0, 1}),
EncodableValue(std::vector<uint8_t>{0, 10}),
// IntList
EncodableValue(std::vector<int32_t>{0, 1}),
EncodableValue(std::vector<int32_t>{0, 100}),
// LongList
EncodableValue(std::vector<int64_t>{0, 1l}),
EncodableValue(std::vector<int64_t>{0, 100l}),
// DoubleList
EncodableValue(std::vector<int64_t>{0, 1l}),
EncodableValue(std::vector<int64_t>{0, 100l}),
// List
EncodableValue(EncodableList{EncodableValue(), EncodableValue(true)}),
EncodableValue(EncodableList{EncodableValue(), EncodableValue(1.0)}),
// Map
EncodableValue(EncodableMap{{EncodableValue(), EncodableValue(true)},
{EncodableValue(7), EncodableValue(7.0)}}),
EncodableValue(
EncodableMap{{EncodableValue(), EncodableValue(1.0)},
{EncodableValue("key"), EncodableValue("value")}}),
};
for (size_t i = 0; i < values.size(); ++i) {
const auto& a = values[i];
for (size_t j = 0; j < values.size(); ++j) {
const auto& b = values[j];
if (i == j) {
// Identical objects should always be equal.
EXPECT_FALSE(a < b);
EXPECT_FALSE(b < a);
} else {
// All other comparisons should be consistent, but the direction doesn't
// matter.
EXPECT_NE(a < b, b < a);
}
}
// Different non-collection objects with the same value should be equal;
// different collections should always be unequal regardless of contents.
bool is_collection = a.IsByteList() || a.IsIntList() || a.IsLongList() ||
a.IsDoubleList() || a.IsList() || a.IsMap();
EncodableValue copy(a);
bool is_equal = !(a < copy || copy < a);
EXPECT_EQ(is_equal, !is_collection);
}
}
// Tests that structures are deep-copied.
TEST(EncodableValueTest, DeepCopy) {
EncodableList encodables = {
EncodableValue(EncodableMap{
{EncodableValue(), EncodableValue(std::vector<int32_t>{1, 2, 3})},
{EncodableValue(1), EncodableValue(10000l)},
{EncodableValue("two"), EncodableValue(7)},
}),
EncodableValue(EncodableList{
EncodableValue(),
EncodableValue(),
EncodableValue(
EncodableMap{{EncodableValue("a"), EncodableValue("b")}}),
}),
};
EncodableValue value(encodables);
ASSERT_TRUE(value.IsList());
// Spot-check innermost collection values.
EXPECT_EQ(value.ListValue()[0].MapValue()[EncodableValue("two")].IntValue(),
7);
EXPECT_EQ(value.ListValue()[1]
.ListValue()[2]
.MapValue()[EncodableValue("a")]
.StringValue(),
"b");
// Modify those values in the original structure.
encodables[0].MapValue()[EncodableValue("two")] = EncodableValue();
encodables[1].ListValue()[2].MapValue()[EncodableValue("a")] = 99;
// Re-check innermost collection values to ensure that they haven't changed.
EXPECT_EQ(value.ListValue()[0].MapValue()[EncodableValue("two")].IntValue(),
7);
EXPECT_EQ(value.ListValue()[1]
.ListValue()[2]
.MapValue()[EncodableValue("a")]
.StringValue(),
"b");
}
} // namespace flutter
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
#include <assert.h>
#include <cstdint>
#include <map>
#include <string>
#include <utility>
#include <vector>
namespace flutter {
static_assert(sizeof(double) == 8, "EncodableValue requires a 64-bit double");
class EncodableValue;
// Convenience type aliases for list and map EncodableValue types.
using EncodableList = std::vector<EncodableValue>;
using EncodableMap = std::map<EncodableValue, EncodableValue>;
// An object that can contain any value or collection type supported by
// Flutter's standard method codec.
//
// For details, see:
// https://api.flutter.dev/flutter/services/StandardMessageCodec-class.html
//
// As an example, the following Dart structure:
// {
// 'flag': true,
// 'name': 'Thing',
// 'values': [1, 2.0, 4],
// }
// would correspond to:
// EncodableValue(EncodableMap{
// {EncodableValue("flag"), EncodableValue(true)},
// {EncodableValue("name"), EncodableValue("Thing")},
// {EncodableValue("values"), EncodableValue(EncodableList{
// EncodableValue(1),
// EncodableValue(2.0),
// EncodableValue(4),
// })},
// })
class EncodableValue {
public:
// Possible types for an EncodableValue to reperesent.
enum class Type {
kNull, // A null value.
kBool, // A boolean value.
kInt, // A 32-bit integer.
kLong, // A 64-bit integer.
kDouble, // A 64-bit floating point number.
kString, // A string.
kByteList, // A list of bytes.
kIntList, // A list of 32-bit integers.
kLongList, // A list of 64-bit integers.
kDoubleList, // A list of 64-bit floating point numbers.
kList, // A list of EncodableValues.
kMap, // A mapping from EncodableValues to EncodableValues.
};
// Creates an instance representing a null value.
EncodableValue() {}
// Creates an instance representing a bool value.
explicit EncodableValue(bool value) : bool_(value), type_(Type::kBool) {}
// Creates an instance representing a 32-bit integer value.
explicit EncodableValue(int32_t value) : int_(value), type_(Type::kInt) {}
// Creates an instance representing a 64-bit integer value.
explicit EncodableValue(int64_t value) : long_(value), type_(Type::kLong) {}
// Creates an instance representing a 64-bit floating point value.
explicit EncodableValue(double value)
: double_(value), type_(Type::kDouble) {}
// Creates an instance representing a string value.
explicit EncodableValue(const char* value)
: string_(new std::string(value)), type_(Type::kString) {}
// Creates an instance representing a string value.
explicit EncodableValue(const std::string& value)
: string_(new std::string(value)), type_(Type::kString) {}
// Creates an instance representing a list of bytes.
explicit EncodableValue(std::vector<uint8_t> list)
: byte_list_(new std::vector<uint8_t>(std::move(list))),
type_(Type::kByteList) {}
// Creates an instance representing a list of 32-bit integers.
explicit EncodableValue(std::vector<int32_t> list)
: int_list_(new std::vector<int32_t>(std::move(list))),
type_(Type::kIntList) {}
// Creates an instance representing a list of 64-bit integers.
explicit EncodableValue(std::vector<int64_t> list)
: long_list_(new std::vector<int64_t>(std::move(list))),
type_(Type::kLongList) {}
// Creates an instance representing a list of 64-bit floating point values.
explicit EncodableValue(std::vector<double> list)
: double_list_(new std::vector<double>(std::move(list))),
type_(Type::kDoubleList) {}
// Creates an instance representing a list of EncodableValues.
explicit EncodableValue(EncodableList list)
: list_(new EncodableList(std::move(list))), type_(Type::kList) {}
// Creates an instance representing a map from EncodableValues to
// EncodableValues.
explicit EncodableValue(EncodableMap map)
: map_(new EncodableMap(std::move(map))), type_(Type::kMap) {}
// Convience constructor for creating default value of the given type.
//
// Collections types will be empty, numeric types will be 0, strings will be
// empty, and booleans will be false. For non-collection types, prefer using
// the value-based constructor with an explicit value for clarity.
explicit EncodableValue(Type type) : type_(type) {
switch (type_) {
case Type::kNull:
break;
case Type::kBool:
bool_ = false;
break;
case Type::kInt:
int_ = 0;
break;
case Type::kLong:
long_ = 0;
break;
case Type::kDouble:
double_ = 0.0;
break;
case Type::kString:
string_ = new std::string();
break;
case Type::kByteList:
byte_list_ = new std::vector<uint8_t>();
break;
case Type::kIntList:
int_list_ = new std::vector<int32_t>();
break;
case Type::kLongList:
long_list_ = new std::vector<int64_t>();
break;
case Type::kDoubleList:
double_list_ = new std::vector<double>();
break;
case Type::kList:
list_ = new std::vector<EncodableValue>();
break;
case Type::kMap:
map_ = new std::map<EncodableValue, EncodableValue>();
break;
}
}
~EncodableValue() { DestroyValue(); }
EncodableValue(const EncodableValue& other) {
DestroyValue();
type_ = other.type_;
switch (type_) {
case Type::kNull:
break;
case Type::kBool:
bool_ = other.bool_;
break;
case Type::kInt:
int_ = other.int_;
break;
case Type::kLong:
long_ = other.long_;
break;
case Type::kDouble:
double_ = other.double_;
break;
case Type::kString:
string_ = new std::string(*other.string_);
break;
case Type::kByteList:
byte_list_ = new std::vector<uint8_t>(*other.byte_list_);
break;
case Type::kIntList:
int_list_ = new std::vector<int32_t>(*other.int_list_);
break;
case Type::kLongList:
long_list_ = new std::vector<int64_t>(*other.long_list_);
break;
case Type::kDoubleList:
double_list_ = new std::vector<double>(*other.double_list_);
break;
case Type::kList:
list_ = new std::vector<EncodableValue>(*other.list_);
break;
case Type::kMap:
map_ = new std::map<EncodableValue, EncodableValue>(*other.map_);
break;
}
}
EncodableValue(EncodableValue&& other) { *this = std::move(other); }
EncodableValue& operator=(const EncodableValue& other) {
if (&other == this) {
return *this;
}
using std::swap;
EncodableValue temp(other);
swap(*this, temp);
return *this;
}
EncodableValue& operator=(EncodableValue&& other) {
if (&other == this) {
return *this;
}
DestroyValue();
type_ = other.type_;
switch (type_) {
case Type::kNull:
break;
case Type::kBool:
bool_ = other.bool_;
break;
case Type::kInt:
int_ = other.int_;
break;
case Type::kLong:
long_ = other.long_;
break;
case Type::kDouble:
double_ = other.double_;
break;
case Type::kString:
string_ = other.string_;
break;
case Type::kByteList:
byte_list_ = other.byte_list_;
break;
case Type::kIntList:
int_list_ = other.int_list_;
break;
case Type::kLongList:
long_list_ = other.long_list_;
break;
case Type::kDoubleList:
double_list_ = other.double_list_;
break;
case Type::kList:
list_ = other.list_;
break;
case Type::kMap:
map_ = other.map_;
break;
}
// Ensure that destruction doesn't run on the source of the move.
other.type_ = Type::kNull;
return *this;
}
// Allow assigning any value type that can be used for a constructor.
template <typename T>
EncodableValue& operator=(const T& value) {
*this = EncodableValue(value);
return *this;
}
// This operator exists only to provide a stable ordering for use as a
// std::map key. It does not attempt to provide useful ordering semantics.
// Notably:
// - Numeric values are not guaranteed any ordering across numeric types.
// E.g., 1 as a Long may sort after 100 as an Int.
// - Collection types use pointer equality, rather than value. This means that
// multiple collections with the same values will end up as separate keys
// in a map (consistent with default Dart Map behavior).
bool operator<(const EncodableValue& other) const {
if (type_ != other.type_) {
return type_ < other.type_;
}
switch (type_) {
case Type::kNull:
return false;
case Type::kBool:
return bool_ < other.bool_;
case Type::kInt:
return int_ < other.int_;
case Type::kLong:
return long_ < other.long_;
case Type::kDouble:
return double_ < other.double_;
case Type::kString:
return *string_ < *other.string_;
case Type::kByteList:
case Type::kIntList:
case Type::kLongList:
case Type::kDoubleList:
case Type::kList:
case Type::kMap:
return this < &other;
}
assert(false);
return false;
}
// Returns the bool value this object represents.
//
// It is a programming error to call this unless IsBool() is true.
bool BoolValue() const {
assert(IsBool());
return bool_;
}
// Returns the 32-bit integer value this object represents.
//
// It is a programming error to call this unless IsInt() is true.
int32_t IntValue() const {
assert(IsInt());
return int_;
}
// Returns the 64-bit integer value this object represents.
//
// It is a programming error to call this unless IsLong() or IsInt() is true.
//
// Note that calling this function on an Int value is the only case where
// a *Value() function can be called without the corresponding Is*() being
// true. This is to simplify handling objects received from Flutter where the
// values may be larger than 32-bit, since they have the same type on the Dart
// side, but will be either 32-bit or 64-bit here depending on the value.
int64_t LongValue() const {
assert(IsLong() || IsInt());
if (IsLong()) {
return long_;
}
return int_;
}
// Returns the double value this object represents.
//
// It is a programming error to call this unless IsDouble() is true.
double DoubleValue() const {
assert(IsDouble());
return double_;
}
// Returns the string value this object represents.
//
// It is a programming error to call this unless IsString() is true.
const std::string& StringValue() const {
assert(IsString());
return *string_;
}
// Returns the byte list this object represents.
//
// It is a programming error to call this unless IsByteList() is true.
const std::vector<uint8_t>& ByteListValue() const {
assert(IsByteList());
return *byte_list_;
}
// Returns the byte list this object represents.
//
// It is a programming error to call this unless IsByteList() is true.
std::vector<uint8_t>& ByteListValue() {
assert(IsByteList());
return *byte_list_;
}
// Returns the 32-bit integer list this object represents.
//
// It is a programming error to call this unless IsIntList() is true.
const std::vector<int32_t>& IntListValue() const {
assert(IsIntList());
return *int_list_;
}
// Returns the 32-bit integer list this object represents.
//
// It is a programming error to call this unless IsIntList() is true.
std::vector<int32_t>& IntListValue() {
assert(IsIntList());
return *int_list_;
}
// Returns the 64-bit integer list this object represents.
//
// It is a programming error to call this unless IsLongList() is true.
const std::vector<int64_t>& LongListValue() const {
assert(IsLongList());
return *long_list_;
}
// Returns the 64-bit integer list this object represents.
//
// It is a programming error to call this unless IsLongList() is true.
std::vector<int64_t>& LongListValue() {
assert(IsLongList());
return *long_list_;
}
// Returns the double list this object represents.
//
// It is a programming error to call this unless IsDoubleList() is true.
const std::vector<double>& DoubleListValue() const {
assert(IsDoubleList());
return *double_list_;
}
// Returns the double list this object represents.
//
// It is a programming error to call this unless IsDoubleList() is true.
std::vector<double>& DoubleListValue() {
assert(IsDoubleList());
return *double_list_;
}
// Returns the list of EncodableValues this object represents.
//
// It is a programming error to call this unless IsList() is true.
const EncodableList& ListValue() const {
assert(IsList());
return *list_;
}
// Returns the list of EncodableValues this object represents.
//
// It is a programming error to call this unless IsList() is true.
EncodableList& ListValue() {
assert(IsList());
return *list_;
}
// Returns the map of EncodableValue : EncodableValue pairs this object
// represent.
//
// It is a programming error to call this unless IsMap() is true.
const EncodableMap& MapValue() const {
assert(IsMap());
return *map_;
}
// Returns the map of EncodableValue : EncodableValue pairs this object
// represent.
//
// It is a programming error to call this unless IsMap() is true.
EncodableMap& MapValue() {
assert(IsMap());
return *map_;
}
// Returns true if this represents a null value.
bool IsNull() const { return type_ == Type::kNull; }
// Returns true if this represents a bool value.
bool IsBool() const { return type_ == Type::kBool; }
// Returns true if this represents a 32-bit integer value.
bool IsInt() const { return type_ == Type::kInt; }
// Returns true if this represents a 64-bit integer value.
bool IsLong() const { return type_ == Type::kLong; }
// Returns true if this represents a double value.
bool IsDouble() const { return type_ == Type::kDouble; }
// Returns true if this represents a string value.
bool IsString() const { return type_ == Type::kString; }
// Returns true if this represents a list of bytes.
bool IsByteList() const { return type_ == Type::kByteList; }
// Returns true if this represents a list of 32-bit integers.
bool IsIntList() const { return type_ == Type::kIntList; }
// Returns true if this represents a list of 64-bit integers.
bool IsLongList() const { return type_ == Type::kLongList; }
// Returns true if this represents a list of doubles.
bool IsDoubleList() const { return type_ == Type::kDoubleList; }
// Returns true if this represents a list of EncodableValues.
bool IsList() const { return type_ == Type::kList; }
// Returns true if this represents a map of EncodableValue : EncodableValue
// pairs.
bool IsMap() const { return type_ == Type::kMap; }
// Returns the type this value represents.
//
// This is primarily intended for use with switch(); for individual checks,
// prefer an Is*() call.
Type type() const { return type_; }
private:
// Performs any cleanup necessary for the active union value. This must be
// called before assigning a new value, and on object destruction.
//
// After calling this, type_ will alway be kNull.
void DestroyValue() {
switch (type_) {
case Type::kNull:
case Type::kBool:
case Type::kInt:
case Type::kLong:
case Type::kDouble:
break;
case Type::kString:
delete string_;
break;
case Type::kByteList:
delete byte_list_;
break;
case Type::kIntList:
delete int_list_;
break;
case Type::kLongList:
delete long_list_;
break;
case Type::kDoubleList:
delete double_list_;
break;
case Type::kList:
delete list_;
break;
case Type::kMap:
delete map_;
break;
}
type_ = Type::kNull;
}
// The anonymous union that stores the represented value. Accessing any of
// these entries other than the one that corresponds to the current value of
// |type_| has undefined behavior.
//
// Pointers are used for the non-POD types to avoid making the overall size
// of the union unnecessarily large.
//
// TODO: Replace this with std::variant once c++17 is available.
union {
bool bool_;
int32_t int_;
int64_t long_;
double double_;
std::string* string_;
std::vector<uint8_t>* byte_list_;
std::vector<int32_t>* int_list_;
std::vector<int64_t>* long_list_;
std::vector<double>* double_list_;
std::vector<EncodableValue>* list_;
std::map<EncodableValue, EncodableValue>* map_;
};
// The currently active union entry.
Type type_ = Type::kNull;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_COMMON_CPP_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册