#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_SEND_VALIDATION_H_
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_ARRAY_SERIALIZATION_SEND_VALIDATION_H_
#include <type_traits>
#include "mojo/public/cpp/bindings/array_data_view.h"
#include "mojo/public/cpp/bindings/lib/array_internal.h"
#include "mojo/public/cpp/bindings/lib/array_serialization.h"
#include "mojo/public/cpp/bindings/lib/message_fragment.h"
#include "mojo/public/cpp/bindings/lib/send_validation.h"
#include "mojo/public/cpp/bindings/lib/validation_errors.h"
namespace mojo::internal {
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator,
typename EnableType = void>
struct SendValidationArraySerializer;
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator,
typename = void>
struct HasSendValidationArraySerializer : std::false_type {};
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator>
struct HasSendValidationArraySerializer<
MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator,
std::void_t<decltype(SendValidationArraySerializer<MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator>{})>>
: std::true_type {};
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator>
using SelectArraySerializer = std::conditional_t<
HasSendValidationArraySerializer<MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator>::value,
SendValidationArraySerializer<MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator>,
ArraySerializer<MojomType, MaybeConstUserType, UserTypeIterator>>;
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator>
requires(!base::is_instantiation<typename MojomType::Element, std::optional>)
struct SendValidationArraySerializer<
MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator,
typename std::enable_if<BelongsTo<typename MojomType::Element,
MojomTypeCategory::kEnum>::value>::type> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Data = typename MojomTypeTraits<MojomType>::Data;
using DataElement = typename Data::Element;
using Element = typename MojomType::Element;
using Traits = ArrayTraits<UserType>;
static_assert(sizeof(Element) == sizeof(DataElement),
"Incorrect array serializer");
static void SerializeElements(
UserTypeIterator* input,
MessageFragment<Data>& fragment,
const ContainerValidateParams* validate_params) {
if constexpr (send_validation == SendValidation::kFatal) {
CHECK(!validate_params->element_is_nullable)
<< "Primitive type should be non-nullable";
CHECK(!validate_params->element_validate_params)
<< "Primitive type should not have array validate params";
} else if constexpr (send_validation == SendValidation::kWarning) {
DCHECK(!validate_params->element_is_nullable)
<< "Primitive type should be non-nullable";
DCHECK(!validate_params->element_validate_params)
<< "Primitive type should not have array validate params";
}
Data* output = fragment.data();
size_t size = input->GetSize();
for (size_t i = 0; i < size; ++i) {
Serialize<Element, send_validation>(input->GetNext(),
output->storage() + i);
}
}
};
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator>
requires(base::is_instantiation<typename MojomType::Element, std::optional>)
struct SendValidationArraySerializer<
MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator,
std::enable_if_t<BelongsTo<typename MojomType::Element,
MojomTypeCategory::kEnum>::value>> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Data = typename MojomTypeTraits<MojomType>::Data;
using DataElement = typename Data::Element;
using Element = typename MojomType::Element;
using Traits = ArrayTraits<UserType>;
static_assert(IsStdOptional<typename Traits::Element>::value,
"Output type should be optional");
static_assert(sizeof(Element) == sizeof(DataElement),
"Incorrect array serializer");
static void SerializeElements(
UserTypeIterator* input,
MessageFragment<Data>& fragment,
const ContainerValidateParams* validate_params) {
if constexpr (send_validation == SendValidation::kFatal) {
CHECK(!validate_params->element_validate_params)
<< "Primitive type should not have array validate params";
} else if constexpr (send_validation == SendValidation::kWarning) {
DCHECK(!validate_params->element_validate_params)
<< "Primitive type should not have array validate params";
}
Data* output = fragment.data();
size_t size = input->GetSize();
for (size_t i = 0; i < size; ++i) {
auto next = input->GetNext();
if (next) {
int32_t serialized;
Serialize<typename Element::value_type, send_validation>(*next,
&serialized);
output->at(i) = serialized;
} else {
output->at(i) = std::nullopt;
}
}
}
};
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator>
struct SendValidationArraySerializer<
MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator,
typename std::enable_if<BelongsTo<
typename MojomType::Element,
MojomTypeCategory::kAssociatedInterface |
MojomTypeCategory::kAssociatedInterfaceRequest |
MojomTypeCategory::kHandle | MojomTypeCategory::kInterface |
MojomTypeCategory::kInterfaceRequest>::value>::type> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Data = typename MojomTypeTraits<MojomType>::Data;
using Element = typename MojomType::Element;
using Traits = ArrayTraits<UserType>;
static void SerializeElements(
UserTypeIterator* input,
MessageFragment<Data>& fragment,
const ContainerValidateParams* validate_params) {
if constexpr (send_validation == SendValidation::kFatal) {
CHECK(!validate_params->element_validate_params)
<< "Handle or interface type should not have array validate params";
} else if constexpr (send_validation == SendValidation::kWarning) {
DCHECK(!validate_params->element_validate_params)
<< "Handle or interface type should not have array validate params";
}
Data* output = fragment.data();
size_t size = input->GetSize();
for (size_t i = 0; i < size; ++i) {
decltype(auto) next = input->GetNext();
Serialize<Element, send_validation>(next, &output->at(i),
&fragment.message());
static const ValidationError kError =
BelongsTo<Element,
MojomTypeCategory::kAssociatedInterface |
MojomTypeCategory::kAssociatedInterfaceRequest>::value
? VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID
: VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE;
MOJO_INTERNAL_CHECK_SERIALIZATION(
send_validation,
!(!validate_params->element_is_nullable &&
!IsHandleOrInterfaceValid(output->at(i))),
kError,
MakeMessageWithArrayIndex("invalid handle or interface ID in array "
"expecting valid handles or interface IDs",
size, i));
}
}
};
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator>
struct SendValidationArraySerializer<
MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator,
typename std::enable_if<
BelongsTo<typename MojomType::Element,
MojomTypeCategory::kArray | MojomTypeCategory::kMap |
MojomTypeCategory::kString |
MojomTypeCategory::kStruct>::value>::type> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Data = typename MojomTypeTraits<MojomType>::Data;
using Element = typename MojomType::Element;
using ElementData = typename MojomTypeTraits<Element>::Data;
using Traits = ArrayTraits<UserType>;
static void SerializeElements(
UserTypeIterator* input,
MessageFragment<Data>& fragment,
const ContainerValidateParams* validate_params) {
size_t size = input->GetSize();
for (size_t i = 0; i < size; ++i) {
MessageFragment<ElementData> data_fragment(fragment.message());
decltype(auto) next = input->GetNext();
SerializeCaller<Element>::Run(next, data_fragment,
validate_params->element_validate_params);
fragment->at(i).Set(data_fragment.is_null() ? nullptr
: data_fragment.data());
MOJO_INTERNAL_CHECK_SERIALIZATION(
send_validation,
!(!validate_params->element_is_nullable && data_fragment.is_null()),
VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
MakeMessageWithArrayIndex("null in array expecting valid pointers",
size, i));
}
}
private:
template <typename T,
bool is_array_or_map = BelongsTo<
T,
MojomTypeCategory::kArray | MojomTypeCategory::kMap>::value>
struct SerializeCaller {
template <typename InputElementType>
static void Run(InputElementType&& input,
MessageFragment<ElementData>& fragment,
const ContainerValidateParams* validate_params) {
Serialize<T, send_validation>(std::forward<InputElementType>(input),
fragment);
}
};
template <typename T>
struct SerializeCaller<T, true> {
template <typename InputElementType>
static void Run(InputElementType&& input,
MessageFragment<ElementData>& fragment,
const ContainerValidateParams* validate_params) {
Serialize<T, send_validation>(std::forward<InputElementType>(input),
fragment, validate_params);
}
};
};
template <typename MojomType,
typename MaybeConstUserType,
SendValidation send_validation,
typename UserTypeIterator>
struct SendValidationArraySerializer<
MojomType,
MaybeConstUserType,
send_validation,
UserTypeIterator,
typename std::enable_if<
BelongsTo<typename MojomType::Element,
MojomTypeCategory::kUnion>::value>::type> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Data = typename MojomTypeTraits<MojomType>::Data;
using Element = typename MojomType::Element;
using DataElement = typename Data::Element;
using Traits = ArrayTraits<UserType>;
static void SerializeElements(
UserTypeIterator* input,
MessageFragment<Data>& fragment,
const ContainerValidateParams* validate_params) {
size_t size = input->GetSize();
for (size_t i = 0; i < size; ++i) {
MessageFragment<DataElement> inlined_union_element(fragment.message());
inlined_union_element.Claim(&fragment->at(i));
decltype(auto) next = input->GetNext();
Serialize<Element, send_validation>(next, inlined_union_element, true);
MOJO_INTERNAL_CHECK_SERIALIZATION(
send_validation,
!(!validate_params->element_is_nullable &&
inlined_union_element.is_null()),
VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
MakeMessageWithArrayIndex("null in array expecting valid unions",
size, i));
}
}
};
template <typename Element,
typename MaybeConstUserType,
SendValidation send_validation>
struct SendValidationSerializer<ArrayDataView<Element>,
MaybeConstUserType,
send_validation> {
using UserType = typename std::remove_const<MaybeConstUserType>::type;
using Traits = ArrayTraits<UserType>;
using Impl = SelectArraySerializer<ArrayDataView<Element>,
MaybeConstUserType,
send_validation,
ArrayIterator<Traits, MaybeConstUserType>>;
using Data = typename MojomTypeTraits<ArrayDataView<Element>>::Data;
static void Serialize(MaybeConstUserType& input,
MessageFragment<Data>& fragment,
const ContainerValidateParams* validate_params) {
if (CallIsNullIfExists<Traits>(input)) {
return;
}
const size_t size = Traits::GetSize(input);
MOJO_INTERNAL_CHECK_SERIALIZATION(
send_validation,
!(validate_params->expected_num_elements != 0 &&
size != validate_params->expected_num_elements),
VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
MakeMessageWithExpectedArraySize(
"fixed-size array has wrong number of elements", size,
validate_params->expected_num_elements));
fragment.AllocateArrayData(size);
ArrayIterator<Traits, MaybeConstUserType> iterator(input);
Impl::SerializeElements(&iterator, fragment, validate_params);
}
};
}
#endif