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