Flutter Engine
The Flutter Engine
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 <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
34namespace flutter {
35
36static_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.
61 public:
62 explicit CustomEncodableValue(const std::any& value) : value_(value) {}
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
91class EncodableValue;
92
93// Convenience type aliases.
94using EncodableList = std::vector<EncodableValue>;
95using EncodableMap = std::map<EncodableValue, EncodableValue>;
96
97namespace 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
103using 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>,
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
165class 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)
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 // Explicitly provide operator<, delegating to std::variant's operator<.
220 // There are issues with with the way the standard library-provided
221 // < and <=> comparisons interact with classes derived from variant.
222 friend bool operator<(const EncodableValue& lhs, const EncodableValue& rhs) {
223 return static_cast<const super&>(lhs) < static_cast<const super&>(rhs);
224 }
225};
226
227} // namespace flutter
228
229#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_
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)
internal::EncodableValueVariant super
EncodableValue(const CustomEncodableValue &v)
friend bool operator<(const EncodableValue &lhs, const EncodableValue &rhs)
constexpr EncodableValue(T &&t) noexcept
uint8_t value
std::vector< EncodableValue > EncodableList
std::map< EncodableValue, EncodableValue > EncodableMap
Definition ref_ptr.h:256
#define T