Avi Drissman | d387f092 | 2022-09-14 20:51:31 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors |
rockot | 85dce086 | 2015-11-13 01:33:59 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Arthur Sonzogni | d4ee545 | 2024-07-18 21:51:54 | [diff] [blame] | 5 | #ifdef UNSAFE_BUFFERS_BUILD |
| 6 | // TODO(crbug.com/351564777): Remove this and convert code to safer constructs. |
| 7 | #pragma allow_unsafe_buffers |
| 8 | #endif |
| 9 | |
rockot | 85dce086 | 2015-11-13 01:33:59 | [diff] [blame] | 10 | #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ |
| 11 | #define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ |
| 12 | |
Avi Drissman | 2e88ac37 | 2015-12-21 18:14:57 | [diff] [blame] | 13 | #include <stddef.h> |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 14 | #include <string.h> // For |memcpy()|. |
rockot | 85dce086 | 2015-11-13 01:33:59 | [diff] [blame] | 15 | |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 16 | #include <type_traits> |
| 17 | #include <utility> |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 18 | |
Emily Andrews | 7f0e194 | 2025-04-25 21:25:26 | [diff] [blame] | 19 | #include "base/check.h" |
Ali Hijazi | 20b1c69 | 2023-01-11 17:47:05 | [diff] [blame] | 20 | #include "base/memory/raw_ptr_exclusion.h" |
yzshen | 6dc9035 | 2016-08-24 09:12:57 | [diff] [blame] | 21 | #include "mojo/public/cpp/bindings/array_data_view.h" |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 22 | #include "mojo/public/cpp/bindings/lib/array_internal.h" |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 23 | #include "mojo/public/cpp/bindings/lib/message_fragment.h" |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 24 | #include "mojo/public/cpp/bindings/lib/serialization_forward.h" |
| 25 | #include "mojo/public/cpp/bindings/lib/template_util.h" |
| 26 | #include "mojo/public/cpp/bindings/lib/validation_errors.h" |
| 27 | |
rockot | 85dce086 | 2015-11-13 01:33:59 | [diff] [blame] | 28 | namespace mojo { |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 29 | |
| 30 | class Message; |
| 31 | |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 32 | namespace internal { |
rockot | 85dce086 | 2015-11-13 01:33:59 | [diff] [blame] | 33 | |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 34 | template <typename Traits, |
| 35 | typename MaybeConstUserType, |
| 36 | bool HasGetBegin = |
| 37 | HasGetBeginMethod<Traits, MaybeConstUserType>::value> |
| 38 | class ArrayIterator {}; |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 39 | |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 40 | // Used as the UserTypeIterator template parameter of ArraySerializer. |
| 41 | template <typename Traits, typename MaybeConstUserType> |
| 42 | class ArrayIterator<Traits, MaybeConstUserType, true> { |
| 43 | public: |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 44 | using IteratorType = |
| 45 | decltype(Traits::GetBegin(std::declval<MaybeConstUserType&>())); |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 46 | |
| 47 | explicit ArrayIterator(MaybeConstUserType& input) |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 48 | : input_(input), iter_(Traits::GetBegin(input)) {} |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 49 | ~ArrayIterator() {} |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 50 | |
| 51 | size_t GetSize() const { return Traits::GetSize(input_); } |
| 52 | |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 53 | decltype(auto) GetNext() { |
| 54 | decltype(auto) value = Traits::GetValue(iter_); |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 55 | Traits::AdvanceIterator(iter_); |
| 56 | return value; |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 57 | } |
| 58 | |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 59 | const MaybeConstUserType& input() const { return input_; } |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 60 | |
| 61 | private: |
Bartek Nowierski | f5eeeba | 2024-01-25 12:49:39 | [diff] [blame] | 62 | // RAW_PTR_EXCLUSION: Binary size increase. |
Ali Hijazi | 20b1c69 | 2023-01-11 17:47:05 | [diff] [blame] | 63 | RAW_PTR_EXCLUSION MaybeConstUserType& input_; |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 64 | IteratorType iter_; |
| 65 | }; |
| 66 | |
| 67 | // Used as the UserTypeIterator template parameter of ArraySerializer. |
| 68 | template <typename Traits, typename MaybeConstUserType> |
| 69 | class ArrayIterator<Traits, MaybeConstUserType, false> { |
| 70 | public: |
| 71 | explicit ArrayIterator(MaybeConstUserType& input) : input_(input), iter_(0) {} |
| 72 | ~ArrayIterator() {} |
| 73 | |
| 74 | size_t GetSize() const { return Traits::GetSize(input_); } |
| 75 | |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 76 | decltype(auto) GetNext() { |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 77 | DCHECK_LT(iter_, Traits::GetSize(input_)); |
| 78 | return Traits::GetAt(input_, iter_++); |
| 79 | } |
| 80 | |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 81 | const MaybeConstUserType& input() const { return input_; } |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 82 | |
| 83 | private: |
Bartek Nowierski | f5eeeba | 2024-01-25 12:49:39 | [diff] [blame] | 84 | // RAW_PTR_EXCLUSION: Binary size increase. |
Ali Hijazi | 20b1c69 | 2023-01-11 17:47:05 | [diff] [blame] | 85 | RAW_PTR_EXCLUSION MaybeConstUserType& input_; |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 86 | size_t iter_; |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 87 | }; |
| 88 | |
| 89 | // ArraySerializer is also used to serialize map keys and values. Therefore, it |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 90 | // has a UserTypeIterator parameter which is an adaptor for reading to hide the |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 91 | // difference between ArrayTraits and MapTraits. |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 92 | template <typename MojomType, |
| 93 | typename MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 94 | typename UserTypeIterator, |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 95 | typename EnableType = void> |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 96 | struct ArraySerializer; |
rockot | 85dce086 | 2015-11-13 01:33:59 | [diff] [blame] | 97 | |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 98 | // Handles serialization and deserialization of arrays of pod types. |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 99 | template <typename MojomType, |
| 100 | typename MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 101 | typename UserTypeIterator> |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 102 | struct ArraySerializer< |
| 103 | MojomType, |
| 104 | MaybeConstUserType, |
| 105 | UserTypeIterator, |
Fred Shih | 4ab323b | 2024-04-04 21:56:29 | [diff] [blame] | 106 | std::enable_if_t<BelongsTo<typename MojomType::Element, |
| 107 | MojomTypeCategory::kPOD>::value>> { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 108 | using UserType = typename std::remove_const<MaybeConstUserType>::type; |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 109 | using Data = typename MojomTypeTraits<MojomType>::Data; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 110 | using DataElement = typename Data::Element; |
| 111 | using Element = typename MojomType::Element; |
| 112 | using Traits = ArrayTraits<UserType>; |
| 113 | |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 114 | static_assert(std::is_same<Element, DataElement>::value, |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 115 | "Incorrect array serializer"); |
Daniel Cheng | 02908b60 | 2017-08-11 08:13:29 | [diff] [blame] | 116 | static_assert( |
| 117 | std::is_same< |
| 118 | Element, |
| 119 | typename std::remove_const<typename Traits::Element>::type>::value, |
| 120 | "Incorrect array serializer"); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 121 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 122 | static void SerializeElements( |
| 123 | UserTypeIterator* input, |
| 124 | MessageFragment<Data>& fragment, |
| 125 | const ContainerValidateParams* validate_params) { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 126 | DCHECK(!validate_params->element_validate_params) |
| 127 | << "Primitive type should not have array validate params"; |
| 128 | |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 129 | size_t size = input->GetSize(); |
| 130 | if (size == 0) |
| 131 | return; |
| 132 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 133 | Data* output = fragment.data(); |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 134 | if constexpr (HasGetDataMethod<Traits, MaybeConstUserType>::value) { |
| 135 | auto data = Traits::GetData(input->input()); |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 136 | memcpy(output->storage(), data, size * sizeof(DataElement)); |
| 137 | } else { |
| 138 | for (size_t i = 0; i < size; ++i) |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 139 | output->at(i) = input->GetNext(); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 140 | } |
| 141 | } |
| 142 | |
| 143 | static bool DeserializeElements(Data* input, |
| 144 | UserType* output, |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 145 | Message* message) { |
fsamuel | 7b3867c | 2016-06-07 08:13:04 | [diff] [blame] | 146 | if (!Traits::Resize(*output, input->size())) |
| 147 | return false; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 148 | if (input->size()) { |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 149 | if constexpr (HasGetDataMethod<Traits, UserType>::value) { |
| 150 | auto data = Traits::GetData(*output); |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 151 | memcpy(data, input->storage(), input->size() * sizeof(DataElement)); |
| 152 | } else { |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 153 | ArrayIterator<Traits, UserType> iterator(*output); |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 154 | for (size_t i = 0; i < input->size(); ++i) |
Fred Shih | 4ab323b | 2024-04-04 21:56:29 | [diff] [blame] | 155 | iterator.GetNext() = static_cast<DataElement>(input->at(i)); |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 156 | } |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 157 | } |
| 158 | return true; |
| 159 | } |
| 160 | }; |
| 161 | |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 162 | // Handles serialization and deserialization of arrays of enum types. |
| 163 | template <typename MojomType, |
| 164 | typename MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 165 | typename UserTypeIterator> |
Daniel Cheng | fb999fd3 | 2025-06-13 02:30:16 | [diff] [blame] | 166 | requires(!base::is_instantiation<typename MojomType::Element, std::optional>) |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 167 | struct ArraySerializer< |
| 168 | MojomType, |
| 169 | MaybeConstUserType, |
| 170 | UserTypeIterator, |
| 171 | typename std::enable_if<BelongsTo<typename MojomType::Element, |
James Cook | 591304d | 2019-08-06 21:23:39 | [diff] [blame] | 172 | MojomTypeCategory::kEnum>::value>::type> { |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 173 | using UserType = typename std::remove_const<MaybeConstUserType>::type; |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 174 | using Data = typename MojomTypeTraits<MojomType>::Data; |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 175 | using DataElement = typename Data::Element; |
| 176 | using Element = typename MojomType::Element; |
| 177 | using Traits = ArrayTraits<UserType>; |
| 178 | |
| 179 | static_assert(sizeof(Element) == sizeof(DataElement), |
| 180 | "Incorrect array serializer"); |
| 181 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 182 | static void SerializeElements( |
| 183 | UserTypeIterator* input, |
| 184 | MessageFragment<Data>& fragment, |
| 185 | const ContainerValidateParams* validate_params) { |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 186 | DCHECK(!validate_params->element_is_nullable) |
| 187 | << "Primitive type should be non-nullable"; |
| 188 | DCHECK(!validate_params->element_validate_params) |
| 189 | << "Primitive type should not have array validate params"; |
| 190 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 191 | Data* output = fragment.data(); |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 192 | size_t size = input->GetSize(); |
| 193 | for (size_t i = 0; i < size; ++i) |
| 194 | Serialize<Element>(input->GetNext(), output->storage() + i); |
| 195 | } |
| 196 | |
| 197 | static bool DeserializeElements(Data* input, |
| 198 | UserType* output, |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 199 | Message* message) { |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 200 | if (!Traits::Resize(*output, input->size())) |
| 201 | return false; |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 202 | ArrayIterator<Traits, UserType> iterator(*output); |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 203 | for (size_t i = 0; i < input->size(); ++i) { |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 204 | if (!Deserialize<Element>(input->at(i), &iterator.GetNext())) |
yzshen | 442cc86 | 2016-06-10 00:34:09 | [diff] [blame] | 205 | return false; |
| 206 | } |
| 207 | return true; |
| 208 | } |
| 209 | }; |
| 210 | |
Fred Shih | 4ab323b | 2024-04-04 21:56:29 | [diff] [blame] | 211 | // Handles serialization and deserialization of arrays of optional enum types. |
| 212 | template <typename MojomType, |
| 213 | typename MaybeConstUserType, |
| 214 | typename UserTypeIterator> |
Daniel Cheng | fb999fd3 | 2025-06-13 02:30:16 | [diff] [blame] | 215 | requires(base::is_instantiation<typename MojomType::Element, std::optional>) |
Fred Shih | 4ab323b | 2024-04-04 21:56:29 | [diff] [blame] | 216 | struct ArraySerializer< |
| 217 | MojomType, |
| 218 | MaybeConstUserType, |
| 219 | UserTypeIterator, |
| 220 | std::enable_if_t<BelongsTo<typename MojomType::Element, |
| 221 | MojomTypeCategory::kEnum>::value>> { |
| 222 | using UserType = typename std::remove_const<MaybeConstUserType>::type; |
| 223 | using Data = typename MojomTypeTraits<MojomType>::Data; |
| 224 | using DataElement = typename Data::Element; |
| 225 | using Element = typename MojomType::Element; |
| 226 | using Traits = ArrayTraits<UserType>; |
| 227 | |
| 228 | static_assert(IsAbslOptional<typename Traits::Element>::value, |
| 229 | "Output type should be optional"); |
| 230 | static_assert(sizeof(Element) == sizeof(DataElement), |
| 231 | "Incorrect array serializer"); |
| 232 | |
| 233 | static void SerializeElements( |
| 234 | UserTypeIterator* input, |
| 235 | MessageFragment<Data>& fragment, |
| 236 | const ContainerValidateParams* validate_params) { |
| 237 | DCHECK(!validate_params->element_validate_params) |
| 238 | << "Primitive type should not have array validate params"; |
| 239 | |
| 240 | Data* output = fragment.data(); |
| 241 | size_t size = input->GetSize(); |
| 242 | for (size_t i = 0; i < size; ++i) { |
| 243 | auto next = input->GetNext(); |
| 244 | if (next) { |
| 245 | int32_t serialized; |
| 246 | Serialize<typename Element::value_type>(*next, &serialized); |
| 247 | output->at(i) = serialized; |
| 248 | } else { |
| 249 | output->at(i) = std::nullopt; |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | static bool DeserializeElements(Data* input, |
| 255 | UserType* output, |
| 256 | Message* message) { |
| 257 | if (!Traits::Resize(*output, input->size())) { |
| 258 | return false; |
| 259 | } |
| 260 | ArrayIterator<Traits, UserType> iterator(*output); |
| 261 | for (size_t i = 0; i < input->size(); ++i) { |
| 262 | std::optional<int32_t> element = input->at(i).ToOptional(); |
| 263 | if (element) { |
| 264 | typename Element::value_type deserialized; |
| 265 | if (!Deserialize<typename Element::value_type>(*element, |
| 266 | &deserialized)) { |
| 267 | return false; |
| 268 | } |
| 269 | iterator.GetNext() = deserialized; |
| 270 | } else { |
| 271 | iterator.GetNext() = std::nullopt; |
| 272 | } |
| 273 | } |
| 274 | return true; |
| 275 | } |
| 276 | }; |
| 277 | |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 278 | // Serializes and deserializes arrays of bools. |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 279 | template <typename MojomType, |
| 280 | typename MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 281 | typename UserTypeIterator> |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 282 | struct ArraySerializer<MojomType, |
| 283 | MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 284 | UserTypeIterator, |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 285 | typename std::enable_if<BelongsTo< |
| 286 | typename MojomType::Element, |
James Cook | 591304d | 2019-08-06 21:23:39 | [diff] [blame] | 287 | MojomTypeCategory::kBoolean>::value>::type> { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 288 | using UserType = typename std::remove_const<MaybeConstUserType>::type; |
| 289 | using Traits = ArrayTraits<UserType>; |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 290 | using Data = typename MojomTypeTraits<MojomType>::Data; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 291 | |
yzshen | 5430084 | 2016-06-16 19:08:56 | [diff] [blame] | 292 | static_assert(std::is_same<bool, typename Traits::Element>::value, |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 293 | "Incorrect array serializer"); |
| 294 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 295 | static void SerializeElements( |
| 296 | UserTypeIterator* input, |
| 297 | MessageFragment<Data>& fragment, |
| 298 | const ContainerValidateParams* validate_params) { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 299 | DCHECK(!validate_params->element_is_nullable) |
| 300 | << "Primitive type should be non-nullable"; |
| 301 | DCHECK(!validate_params->element_validate_params) |
| 302 | << "Primitive type should not have array validate params"; |
| 303 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 304 | Data* output = fragment.data(); |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 305 | size_t size = input->GetSize(); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 306 | for (size_t i = 0; i < size; ++i) |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 307 | output->at(i) = input->GetNext(); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 308 | } |
| 309 | static bool DeserializeElements(Data* input, |
| 310 | UserType* output, |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 311 | Message* message) { |
fsamuel | 7b3867c | 2016-06-07 08:13:04 | [diff] [blame] | 312 | if (!Traits::Resize(*output, input->size())) |
| 313 | return false; |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 314 | ArrayIterator<Traits, UserType> iterator(*output); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 315 | for (size_t i = 0; i < input->size(); ++i) |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 316 | iterator.GetNext() = input->at(i); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 317 | return true; |
| 318 | } |
| 319 | }; |
| 320 | |
yzshen | f26b053 | 2016-06-30 01:37:59 | [diff] [blame] | 321 | // Serializes and deserializes arrays of handles or interfaces. |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 322 | template <typename MojomType, |
| 323 | typename MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 324 | typename UserTypeIterator> |
yzshen | f26b053 | 2016-06-30 01:37:59 | [diff] [blame] | 325 | struct ArraySerializer< |
| 326 | MojomType, |
| 327 | MaybeConstUserType, |
| 328 | UserTypeIterator, |
James Cook | 591304d | 2019-08-06 21:23:39 | [diff] [blame] | 329 | typename std::enable_if<BelongsTo< |
| 330 | typename MojomType::Element, |
| 331 | MojomTypeCategory::kAssociatedInterface | |
| 332 | MojomTypeCategory::kAssociatedInterfaceRequest | |
| 333 | MojomTypeCategory::kHandle | MojomTypeCategory::kInterface | |
| 334 | MojomTypeCategory::kInterfaceRequest>::value>::type> { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 335 | using UserType = typename std::remove_const<MaybeConstUserType>::type; |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 336 | using Data = typename MojomTypeTraits<MojomType>::Data; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 337 | using Element = typename MojomType::Element; |
| 338 | using Traits = ArrayTraits<UserType>; |
| 339 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 340 | static void SerializeElements( |
| 341 | UserTypeIterator* input, |
| 342 | MessageFragment<Data>& fragment, |
| 343 | const ContainerValidateParams* validate_params) { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 344 | DCHECK(!validate_params->element_validate_params) |
yzshen | f26b053 | 2016-06-30 01:37:59 | [diff] [blame] | 345 | << "Handle or interface type should not have array validate params"; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 346 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 347 | Data* output = fragment.data(); |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 348 | size_t size = input->GetSize(); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 349 | for (size_t i = 0; i < size; ++i) { |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 350 | decltype(auto) next = input->GetNext(); |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 351 | Serialize<Element>(next, &output->at(i), &fragment.message()); |
yzshen | f26b053 | 2016-06-30 01:37:59 | [diff] [blame] | 352 | |
| 353 | static const ValidationError kError = |
| 354 | BelongsTo<Element, |
James Cook | 591304d | 2019-08-06 21:23:39 | [diff] [blame] | 355 | MojomTypeCategory::kAssociatedInterface | |
| 356 | MojomTypeCategory::kAssociatedInterfaceRequest>::value |
yzshen | f26b053 | 2016-06-30 01:37:59 | [diff] [blame] | 357 | ? VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID |
| 358 | : VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE; |
Emily Andrews | 92983e93 | 2025-05-08 16:02:13 | [diff] [blame] | 359 | |
| 360 | MOJO_INTERNAL_CHECK_SERIALIZATION( |
| 361 | SendValidation::kDefault, |
| 362 | !(!validate_params->element_is_nullable && |
| 363 | !IsHandleOrInterfaceValid(output->at(i))), |
yzshen | f26b053 | 2016-06-30 01:37:59 | [diff] [blame] | 364 | kError, |
| 365 | MakeMessageWithArrayIndex("invalid handle or interface ID in array " |
| 366 | "expecting valid handles or interface IDs", |
| 367 | size, i)); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 368 | } |
| 369 | } |
| 370 | static bool DeserializeElements(Data* input, |
| 371 | UserType* output, |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 372 | Message* message) { |
fsamuel | 7b3867c | 2016-06-07 08:13:04 | [diff] [blame] | 373 | if (!Traits::Resize(*output, input->size())) |
| 374 | return false; |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 375 | ArrayIterator<Traits, UserType> iterator(*output); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 376 | for (size_t i = 0; i < input->size(); ++i) { |
yzshen | f26b053 | 2016-06-30 01:37:59 | [diff] [blame] | 377 | bool result = |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 378 | Deserialize<Element>(&input->at(i), &iterator.GetNext(), message); |
yzshen | f26b053 | 2016-06-30 01:37:59 | [diff] [blame] | 379 | DCHECK(result); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 380 | } |
| 381 | return true; |
| 382 | } |
| 383 | }; |
| 384 | |
| 385 | // This template must only apply to pointer mojo entity (strings, structs, |
| 386 | // arrays and maps). |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 387 | template <typename MojomType, |
| 388 | typename MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 389 | typename UserTypeIterator> |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 390 | struct ArraySerializer<MojomType, |
| 391 | MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 392 | UserTypeIterator, |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 393 | typename std::enable_if<BelongsTo< |
| 394 | typename MojomType::Element, |
James Cook | 591304d | 2019-08-06 21:23:39 | [diff] [blame] | 395 | MojomTypeCategory::kArray | MojomTypeCategory::kMap | |
| 396 | MojomTypeCategory::kString | |
| 397 | MojomTypeCategory::kStruct>::value>::type> { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 398 | using UserType = typename std::remove_const<MaybeConstUserType>::type; |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 399 | using Data = typename MojomTypeTraits<MojomType>::Data; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 400 | using Element = typename MojomType::Element; |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 401 | using ElementData = typename MojomTypeTraits<Element>::Data; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 402 | using Traits = ArrayTraits<UserType>; |
| 403 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 404 | static void SerializeElements( |
| 405 | UserTypeIterator* input, |
| 406 | MessageFragment<Data>& fragment, |
| 407 | const ContainerValidateParams* validate_params) { |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 408 | size_t size = input->GetSize(); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 409 | for (size_t i = 0; i < size; ++i) { |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 410 | MessageFragment<ElementData> data_fragment(fragment.message()); |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 411 | decltype(auto) next = input->GetNext(); |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 412 | SerializeCaller<Element>::Run(next, data_fragment, |
| 413 | validate_params->element_validate_params); |
| 414 | fragment->at(i).Set(data_fragment.is_null() ? nullptr |
| 415 | : data_fragment.data()); |
Emily Andrews | 92983e93 | 2025-05-08 16:02:13 | [diff] [blame] | 416 | |
| 417 | MOJO_INTERNAL_CHECK_SERIALIZATION( |
| 418 | SendValidation::kDefault, |
| 419 | !(!validate_params->element_is_nullable && data_fragment.is_null()), |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 420 | VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, |
| 421 | MakeMessageWithArrayIndex("null in array expecting valid pointers", |
| 422 | size, i)); |
| 423 | } |
| 424 | } |
| 425 | static bool DeserializeElements(Data* input, |
| 426 | UserType* output, |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 427 | Message* message) { |
fsamuel | 7b3867c | 2016-06-07 08:13:04 | [diff] [blame] | 428 | if (!Traits::Resize(*output, input->size())) |
| 429 | return false; |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 430 | ArrayIterator<Traits, UserType> iterator(*output); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 431 | for (size_t i = 0; i < input->size(); ++i) { |
yzshen | a601f03 | 2016-07-01 16:14:14 | [diff] [blame] | 432 | if (!Deserialize<Element>(input->at(i).Get(), &iterator.GetNext(), |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 433 | message)) |
yzshen | a601f03 | 2016-07-01 16:14:14 | [diff] [blame] | 434 | return false; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 435 | } |
yzshen | a601f03 | 2016-07-01 16:14:14 | [diff] [blame] | 436 | return true; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | private: |
| 440 | template <typename T, |
James Cook | 591304d | 2019-08-06 21:23:39 | [diff] [blame] | 441 | bool is_array_or_map = BelongsTo< |
| 442 | T, |
| 443 | MojomTypeCategory::kArray | MojomTypeCategory::kMap>::value> |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 444 | struct SerializeCaller { |
| 445 | template <typename InputElementType> |
| 446 | static void Run(InputElementType&& input, |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 447 | MessageFragment<ElementData>& fragment, |
| 448 | const ContainerValidateParams* validate_params) { |
| 449 | Serialize<T>(std::forward<InputElementType>(input), fragment); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 450 | } |
| 451 | }; |
| 452 | |
| 453 | template <typename T> |
| 454 | struct SerializeCaller<T, true> { |
| 455 | template <typename InputElementType> |
| 456 | static void Run(InputElementType&& input, |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 457 | MessageFragment<ElementData>& fragment, |
| 458 | const ContainerValidateParams* validate_params) { |
| 459 | Serialize<T>(std::forward<InputElementType>(input), fragment, |
| 460 | validate_params); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 461 | } |
| 462 | }; |
| 463 | }; |
| 464 | |
| 465 | // Handles serialization and deserialization of arrays of unions. |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 466 | template <typename MojomType, |
| 467 | typename MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 468 | typename UserTypeIterator> |
James Cook | 591304d | 2019-08-06 21:23:39 | [diff] [blame] | 469 | struct ArraySerializer<MojomType, |
| 470 | MaybeConstUserType, |
| 471 | UserTypeIterator, |
| 472 | typename std::enable_if< |
| 473 | BelongsTo<typename MojomType::Element, |
| 474 | MojomTypeCategory::kUnion>::value>::type> { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 475 | using UserType = typename std::remove_const<MaybeConstUserType>::type; |
yzshen | 5e5173a | 2016-06-22 21:49:01 | [diff] [blame] | 476 | using Data = typename MojomTypeTraits<MojomType>::Data; |
yzshen | 5527dbce | 2016-05-10 18:22:04 | [diff] [blame] | 477 | using Element = typename MojomType::Element; |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 478 | using DataElement = typename Data::Element; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 479 | using Traits = ArrayTraits<UserType>; |
| 480 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 481 | static void SerializeElements( |
| 482 | UserTypeIterator* input, |
| 483 | MessageFragment<Data>& fragment, |
| 484 | const ContainerValidateParams* validate_params) { |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 485 | size_t size = input->GetSize(); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 486 | for (size_t i = 0; i < size; ++i) { |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 487 | MessageFragment<DataElement> inlined_union_element(fragment.message()); |
| 488 | inlined_union_element.Claim(fragment->storage() + i); |
Daniel Cheng | e7aa026 | 2022-02-25 20:39:17 | [diff] [blame] | 489 | decltype(auto) next = input->GetNext(); |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 490 | Serialize<Element>(next, inlined_union_element, true); |
Emily Andrews | 92983e93 | 2025-05-08 16:02:13 | [diff] [blame] | 491 | |
| 492 | MOJO_INTERNAL_CHECK_SERIALIZATION( |
| 493 | SendValidation::kDefault, |
| 494 | !(!validate_params->element_is_nullable && |
| 495 | inlined_union_element.is_null()), |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 496 | VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, |
| 497 | MakeMessageWithArrayIndex("null in array expecting valid unions", |
| 498 | size, i)); |
| 499 | } |
| 500 | } |
| 501 | |
| 502 | static bool DeserializeElements(Data* input, |
| 503 | UserType* output, |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 504 | Message* message) { |
fsamuel | 7b3867c | 2016-06-07 08:13:04 | [diff] [blame] | 505 | if (!Traits::Resize(*output, input->size())) |
| 506 | return false; |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 507 | ArrayIterator<Traits, UserType> iterator(*output); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 508 | for (size_t i = 0; i < input->size(); ++i) { |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 509 | if (!Deserialize<Element>(&input->at(i), &iterator.GetNext(), message)) |
yzshen | a601f03 | 2016-07-01 16:14:14 | [diff] [blame] | 510 | return false; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 511 | } |
yzshen | a601f03 | 2016-07-01 16:14:14 | [diff] [blame] | 512 | return true; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 513 | } |
| 514 | }; |
| 515 | |
| 516 | template <typename Element, typename MaybeConstUserType> |
yzshen | 6dc9035 | 2016-08-24 09:12:57 | [diff] [blame] | 517 | struct Serializer<ArrayDataView<Element>, MaybeConstUserType> { |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 518 | using UserType = typename std::remove_const<MaybeConstUserType>::type; |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 519 | using Traits = ArrayTraits<UserType>; |
yzshen | 6dc9035 | 2016-08-24 09:12:57 | [diff] [blame] | 520 | using Impl = ArraySerializer<ArrayDataView<Element>, |
yzshen | 507ce126 | 2016-05-31 18:08:30 | [diff] [blame] | 521 | MaybeConstUserType, |
fsamuel | 09ab696 | 2016-06-13 17:56:53 | [diff] [blame] | 522 | ArrayIterator<Traits, MaybeConstUserType>>; |
yzshen | 6dc9035 | 2016-08-24 09:12:57 | [diff] [blame] | 523 | using Data = typename MojomTypeTraits<ArrayDataView<Element>>::Data; |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 524 | |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 525 | static void Serialize(MaybeConstUserType& input, |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 526 | MessageFragment<Data>& fragment, |
| 527 | const ContainerValidateParams* validate_params) { |
Ken Rockot | 7c91af2d | 2017-07-28 09:54:40 | [diff] [blame] | 528 | if (CallIsNullIfExists<Traits>(input)) |
| 529 | return; |
| 530 | |
| 531 | const size_t size = Traits::GetSize(input); |
Emily Andrews | 92983e93 | 2025-05-08 16:02:13 | [diff] [blame] | 532 | |
| 533 | MOJO_INTERNAL_CHECK_SERIALIZATION( |
| 534 | SendValidation::kDefault, |
| 535 | !(validate_params->expected_num_elements != 0 && |
| 536 | size != validate_params->expected_num_elements), |
| 537 | VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, |
| 538 | MakeMessageWithExpectedArraySize( |
Ken Rockot | 7c91af2d | 2017-07-28 09:54:40 | [diff] [blame] | 539 | "fixed-size array has wrong number of elements", size, |
| 540 | validate_params->expected_num_elements)); |
Emily Andrews | 92983e93 | 2025-05-08 16:02:13 | [diff] [blame] | 541 | |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 542 | fragment.AllocateArrayData(size); |
Ken Rockot | 7c91af2d | 2017-07-28 09:54:40 | [diff] [blame] | 543 | ArrayIterator<Traits, MaybeConstUserType> iterator(input); |
Ken Rockot | cae3ce2 | 2021-02-11 05:34:25 | [diff] [blame] | 544 | Impl::SerializeElements(&iterator, fragment, validate_params); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 545 | } |
| 546 | |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 547 | static bool Deserialize(Data* input, UserType* output, Message* message) { |
yzshen | 2017646 | 2016-05-13 04:42:22 | [diff] [blame] | 548 | if (!input) |
| 549 | return CallSetToNullIfExists<Traits>(output); |
Ken Rockot | 51df42e7 | 2021-02-09 01:20:53 | [diff] [blame] | 550 | return Impl::DeserializeElements(input, output, message); |
yzshen | c8c4b08 | 2016-05-06 21:26:11 | [diff] [blame] | 551 | } |
| 552 | }; |
| 553 | |
| 554 | } // namespace internal |
rockot | 85dce086 | 2015-11-13 01:33:59 | [diff] [blame] | 555 | } // namespace mojo |
| 556 | |
| 557 | #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_H_ |