| Flutter iOS Embedder |

encodable_value.h
Go to the documentation of this file.
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_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
6 #define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
7
8 #include <any>
9 #include <cassert>
10 #include <cstdint>
11 #include <map>
12 #include <string>
13 #include <utility>
14 #include <variant>
15 #include <vector>
16
17 // Unless overridden, attempt to detect the RTTI state from the compiler.
18 #ifndef FLUTTER_ENABLE_RTTI
19 #if defined(_MSC_VER)
20 #ifdef _CPPRTTI
21 #define FLUTTER_ENABLE_RTTI 1
22 #endif
23 #elif defined(__clang__)
24 #if __has_feature(cxx_rtti)
25 #define FLUTTER_ENABLE_RTTI 1
26 #endif
27 #elif defined(__GNUC__)
28 #ifdef __GXX_RTTI
29 #define FLUTTER_ENABLE_RTTI 1
30 #endif
31 #endif
32 #endif // #ifndef FLUTTER_ENABLE_RTTI
33
34 namespace flutter {
35
36 static_assert(sizeof(double) == 8, "EncodableValue requires a 64-bit double");
37
38 // A container for arbitrary types in EncodableValue.
39 //
40 // This is used in conjunction with StandardCodecExtension to allow using other
41 // types with a StandardMethodCodec/StandardMessageCodec. It is implicitly
42 // convertible to EncodableValue, so constructing an EncodableValue from a
43 // custom type can generally be written as:
44 // CustomEncodableValue(MyType(...))
45 // rather than:
46 // EncodableValue(CustomEncodableValue(MyType(...)))
47 //
48 // For extracting received custom types, it is implicitly convertible to
49 // std::any. For example:
50 // const MyType& my_type_value =
51 // std::any_cast<MyType>(std::get<CustomEncodableValue>(value));
52 //
53 // If RTTI is enabled, different extension types can be checked with type():
54 // if (custom_value->type() == typeid(SomeData)) { ... }
55 // Clients that wish to disable RTTI would need to decide on another approach
56 // for distinguishing types (e.g., in StandardCodecExtension::WriteValueOfType)
57 // if multiple custom types are needed. For instance, wrapping all of the
58 // extension types in an EncodableValue-style variant, and only ever storing
59 // that variant in CustomEncodableValue.
60 class CustomEncodableValue {
61 public:
62 explicit CustomEncodableValue(const std::any& value) : value_(value) {}
63 ~CustomEncodableValue() = default;
64
65 // Allow implicit conversion to std::any to allow direct use of any_cast.
66 // NOLINTNEXTLINE(google-explicit-constructor)
67 operator std::any&() { return value_; }
68 // NOLINTNEXTLINE(google-explicit-constructor)
69 operator const std::any&() const { return value_; }
70
71 #if defined(FLUTTER_ENABLE_RTTI) && FLUTTER_ENABLE_RTTI
72 // Passthrough to std::any's type().
73 const std::type_info& type() const noexcept { return value_.type(); }
74 #endif
75
76 // This operator exists only to provide a stable ordering for use as a
77 // std::map key, to satisfy the compiler requirements for EncodableValue.
78 // It does not attempt to provide useful ordering semantics, and using a
79 // custom value as a map key is not recommended.
80 bool operator<(const CustomEncodableValue& other) const {
81 return this < &other;
82 }
83 bool operator==(const CustomEncodableValue& other) const {
84 return this == &other;
85 }
86
87 private:
88 std::any value_;
89 };
90
91 class EncodableValue;
92
93 // Convenience type aliases.
94 using EncodableList = std::vector<EncodableValue>;
95 using EncodableMap = std::map<EncodableValue, EncodableValue>;
96
97 namespace internal {
98 // The base class for EncodableValue. Do not use this directly; it exists only
99 // for EncodableValue to inherit from.
100 //
101 // Do not change the order or indexes of the items here; see the comment on
102 // EncodableValue
103 using EncodableValueVariant = std::variant<std::monostate,
104 bool,
105 int32_t,
106 int64_t,
107 double,
108 std::string,
109 std::vector<uint8_t>,
110 std::vector<int32_t>,
111 std::vector<int64_t>,
112 std::vector<double>,
113 EncodableList,
114 EncodableMap,
115 CustomEncodableValue,
116 std::vector<float>>;
117 } // namespace internal
118
119 // An object that can contain any value or collection type supported by
120 // Flutter's standard method codec.
121 //
122 // For details, see:
123 // https://api.flutter.dev/flutter/services/StandardMessageCodec-class.html
124 //
125 // As an example, the following Dart structure:
126 // {
127 // 'flag': true,
128 // 'name': 'Thing',
129 // 'values': [1, 2.0, 4],
130 // }
131 // would correspond to:
132 // EncodableValue(EncodableMap{
133 // {EncodableValue("flag"), EncodableValue(true)},
134 // {EncodableValue("name"), EncodableValue("Thing")},
135 // {EncodableValue("values"), EncodableValue(EncodableList{
136 // EncodableValue(1),
137 // EncodableValue(2.0),
138 // EncodableValue(4),
139 // })},
140 // })
141 //
142 // The primary API surface for this object is std::variant. For instance,
143 // getting a string value from an EncodableValue, with type checking:
144 // if (std::holds_alternative<std::string>(value)) {
145 // std::string some_string = std::get<std::string>(value);
146 // }
147 //
148 // The order/indexes of the variant types is part of the API surface, and is
149 // guaranteed not to change.
150 //
151 // The variant types are mapped with Dart types in following ways:
152 // std::monostate -> null
153 // bool -> bool
154 // int32_t -> int
155 // int64_t -> int
156 // double -> double
157 // std::string -> String
158 // std::vector<uint8_t> -> Uint8List
159 // std::vector<int32_t> -> Int32List
160 // std::vector<int64_t> -> Int64List
161 // std::vector<float> -> Float32List
162 // std::vector<double> -> Float64List
163 // EncodableList -> List
164 // EncodableMap -> Map
165 class EncodableValue : public internal::EncodableValueVariant {
166 public:
167 // Rely on std::variant for most of the constructors/operators.
168 using super = internal::EncodableValueVariant;
169 using super::super;
170 using super::operator=;
171
172 explicit EncodableValue() = default;
173
174 // Avoid the C++17 pitfall of conversion from char* to bool. Should not be
175 // needed for C++20.
176 explicit EncodableValue(const char* string) : super(std::string(string)) {}
177 EncodableValue& operator=(const char* other) {
178 *this = std::string(other);
179 return *this;
180 }
181
182 // Allow implicit conversion from CustomEncodableValue; the only reason to
183 // make a CustomEncodableValue (which can only be constructed explicitly) is
184 // to use it with EncodableValue, so the risk of unintended conversions is
185 // minimal, and it avoids the need for the verbose:
186 // EncodableValue(CustomEncodableValue(...)).
187 // NOLINTNEXTLINE(google-explicit-constructor)
188 EncodableValue(const CustomEncodableValue& v) : super(v) {}
189
190 // Override the conversion constructors from std::variant to make them
191 // explicit, to avoid implicit conversion.
192 //
193 // While implicit conversion can be convenient in some cases, it can have very
194 // surprising effects. E.g., calling a function that takes an EncodableValue
195 // but accidentally passing an EncodableValue* would, instead of failing to
196 // compile, go through a pointer->bool->EncodableValue(bool) chain and
197 // silently call the function with a temp-constructed EncodableValue(true).
198 template <class T>
199 constexpr explicit EncodableValue(T&& t) noexcept : super(t) {}
200
201 // Returns true if the value is null. Convenience wrapper since unlike the
202 // other types, std::monostate uses aren't self-documenting.
203 bool IsNull() const { return std::holds_alternative<std::monostate>(*this); }
204
205 // Convenience method to simplify handling objects received from Flutter
206 // where the values may be larger than 32-bit, since they have the same type
207 // on the Dart side, but will be either 32-bit or 64-bit here depending on
208 // the value.
209 //
210 // Calling this method if the value doesn't contain either an int32_t or an
211 // int64_t will throw an exception.
212 int64_t LongValue() const {
213 if (std::holds_alternative<int32_t>(*this)) {
214 return std::get<int32_t>(*this);
215 }
216 return std::get<int64_t>(*this);
217 }
218
219 // The C++ Standard Library implementations can get into issues with recursive
220 // constraint satisfaction when (among other things) objects of this type (which
221 // is an `std::variant` subclass) are put into containers like `std::vector`.
222 //
223 // A definition of `operator<` is provided to break that recursion. However, in
224 // C++20 with the latest compilers (Clang compilers newer than 20 and the latest
225 // GCC variants, see https://gcc.godbolt.org/z/KM6n6qane) requiring that that
226 // the `std::three_way_comparable` constraint be satisfied requires the
227 // provision of `operator<=>` to do the same thing.
228 //
229 // The code below makes this translation unit be safe to include from both C++17
230 // and C++20 translation units while also using the newest compilers.
231 //
232 // The correctness of the compiler's gripes with this code and the subsequent
233 // need for these workarounds is not fully understood or explored. If you run
234 // into issues with this code again, the following breadcrumbs may prove
235 // useful. If you cannot access some or all of these links, the compiler
236 // explorer link above should serve a reduced test case to base an investigation
237 // off of.
238 //
239 // * b/423885648#comment8
240 // * b/423885648#comment19
241 // * cl/542631351
242 // * cl/542541552
243 // * https://github.com/flutter/engine/pull/43091
244 //
245 #if __cplusplus >= 202002L
246 friend std::partial_ordering operator<=>(const EncodableValue& lhs,
247 const EncodableValue& rhs) {
248 auto& lv = static_cast<const super&>(lhs);
249 auto& rv = static_cast<const super&>(rhs);
250
251 if (lv < rv) {
252 return std::partial_ordering::less;
253 }
254
255 if (rv < lv) {
256 return std::partial_ordering::greater;
257 }
258
259 if (lv == rv) {
260 return std::partial_ordering::equivalent;
261 }
262
263 return std::partial_ordering::unordered;
264 }
265 #else // __cplusplus >= 202002L
266 friend bool operator<(const EncodableValue& lhs, const EncodableValue& rhs) {
267 return static_cast<const super&>(lhs) < static_cast<const super&>(rhs);
268 }
269 #endif // __cplusplus >= 202002L
270 };
271
272 } // namespace flutter
273
274 #endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
flutter::CustomEncodableValue
Definition: encodable_value.h:60
flutter::CustomEncodableValue::CustomEncodableValue
CustomEncodableValue(const std::any &value)
Definition: encodable_value.h:62
flutter::CustomEncodableValue::~CustomEncodableValue
~CustomEncodableValue()=default
flutter::CustomEncodableValue::operator==
bool operator==(const CustomEncodableValue &other) const
Definition: encodable_value.h:83
flutter::CustomEncodableValue::operator<
bool operator<(const CustomEncodableValue &other) const
Definition: encodable_value.h:80
flutter::EncodableValue
Definition: encodable_value.h:165
flutter::EncodableValue::EncodableValue
EncodableValue(const char *string)
Definition: encodable_value.h:176
flutter::EncodableValue::IsNull
bool IsNull() const
Definition: encodable_value.h:203
flutter::EncodableValue::operator=
EncodableValue & operator=(const char *other)
Definition: encodable_value.h:177
flutter::EncodableValue::EncodableValue
EncodableValue()=default
flutter::EncodableValue::super
internal::EncodableValueVariant super
Definition: encodable_value.h:168
flutter::EncodableValue::EncodableValue
EncodableValue(const CustomEncodableValue &v)
Definition: encodable_value.h:188
flutter::EncodableValue::LongValue
int64_t LongValue() const
Definition: encodable_value.h:212
flutter::EncodableValue::operator<
friend bool operator<(const EncodableValue &lhs, const EncodableValue &rhs)
Definition: encodable_value.h:266
flutter::EncodableValue::EncodableValue
constexpr EncodableValue(T &&t) noexcept
Definition: encodable_value.h:199
flutter::internal::EncodableValueVariant
std::variant< std::monostate, bool, int32_t, int64_t, double, std::string, std::vector< uint8_t >, std::vector< int32_t >, std::vector< int64_t >, std::vector< double >, EncodableList, EncodableMap, CustomEncodableValue, std::vector< float > > EncodableValueVariant
Definition: encodable_value.h:116
flutter
Definition: accessibility_bridge.h:26
flutter::EncodableList
std::vector< EncodableValue > EncodableList
Definition: encodable_value.h:94
flutter::EncodableMap
std::map< EncodableValue, EncodableValue > EncodableMap
Definition: encodable_value.h:95