mojo::Serialize*_() calls now propogate/return validation errors. The public-facing API can use these, but will probably want to use a separate enum of errors (since ValidationError is namespace'd as internal, and should probably remain so). For now, a public serialization API can return a boolean. R=viettrungluu@chromium.org CC=jamesr@chromium.org BUG= Review URL: https://codereview.chromium.org/1387993002 .
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h index dc98245..effec05 100644 --- a/mojo/public/cpp/bindings/lib/array_serialization.h +++ b/mojo/public/cpp/bindings/lib/array_serialization.h
@@ -45,32 +45,38 @@ } template <typename Iterator> - static void SerializeElements(Iterator it, - size_t num_elements, - Buffer* buf, - Array_Data<F>* output, - const ArrayValidateParams* validate_params) { + static ValidationError SerializeElements( + Iterator it, + size_t num_elements, + Buffer* buf, + Array_Data<F>* output, + const ArrayValidateParams* validate_params) { MOJO_DCHECK(!validate_params->element_is_nullable) << "Primitive type should be non-nullable"; MOJO_DCHECK(!validate_params->element_validate_params) << "Primitive type should not have array validate params"; for (size_t i = 0; i < num_elements; ++i, ++it) output->at(i) = *it; + + return VALIDATION_ERROR_NONE; } // We can optimize serializing PODs by |memcpy|ing directly. // Note that this has precedence over its templated sibling defined above. - static void SerializeElements(typename Array<E>::Iterator it, - size_t num_elements, - Buffer* buf, - Array_Data<F>* output, - const ArrayValidateParams* validate_params) { + static ValidationError SerializeElements( + typename Array<E>::Iterator it, + size_t num_elements, + Buffer* buf, + Array_Data<F>* output, + const ArrayValidateParams* validate_params) { MOJO_DCHECK(!validate_params->element_is_nullable) << "Primitive type should be non-nullable"; MOJO_DCHECK(!validate_params->element_validate_params) << "Primitive type should not have array validate params"; if (num_elements) memcpy(output->storage(), &(*it), num_elements * sizeof(E)); + + return VALIDATION_ERROR_NONE; } static void DeserializeElements(Array_Data<F>* input, Array<E>* output) { @@ -89,11 +95,12 @@ } template <typename Iterator> - static void SerializeElements(Iterator it, - size_t num_elements, - Buffer* buf, - Array_Data<bool>* output, - const ArrayValidateParams* validate_params) { + static ValidationError SerializeElements( + Iterator it, + size_t num_elements, + Buffer* buf, + Array_Data<bool>* output, + const ArrayValidateParams* validate_params) { MOJO_DCHECK(!validate_params->element_is_nullable) << "Primitive type should be non-nullable"; MOJO_DCHECK(!validate_params->element_validate_params) @@ -102,6 +109,8 @@ // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy? for (size_t i = 0; i < num_elements; ++i, ++it) output->at(i) = *it; + + return VALIDATION_ERROR_NONE; } static void DeserializeElements(Array_Data<bool>* input, @@ -122,24 +131,29 @@ } template <typename Iterator> - static void SerializeElements(Iterator it, - size_t num_elements, - Buffer* buf, - Array_Data<H>* output, - const ArrayValidateParams* validate_params) { + static ValidationError SerializeElements( + Iterator it, + size_t num_elements, + Buffer* buf, + Array_Data<H>* output, + const ArrayValidateParams* validate_params) { MOJO_DCHECK(!validate_params->element_validate_params) << "Handle type should not have array validate params"; for (size_t i = 0; i < num_elements; ++i, ++it) { // Transfer ownership of the handle. output->at(i) = it->release(); - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !validate_params->element_is_nullable && !output->at(i).is_valid(), - VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, - MakeMessageWithArrayIndex( - "invalid handle in array expecting valid handles", num_elements, - i)); + if (!validate_params->element_is_nullable && !output->at(i).is_valid()) { + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, + MakeMessageWithArrayIndex( + "invalid handle in array expecting valid handles", num_elements, + i)); + return VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE; + } } + + return VALIDATION_ERROR_NONE; } static void DeserializeElements(Array_Data<H>* input, @@ -171,22 +185,30 @@ } template <typename Iterator> - static void SerializeElements(Iterator it, - size_t num_elements, - Buffer* buf, - Array_Data<S_Data*>* output, - const ArrayValidateParams* validate_params) { + static ValidationError SerializeElements( + Iterator it, + size_t num_elements, + Buffer* buf, + Array_Data<S_Data*>* output, + const ArrayValidateParams* validate_params) { for (size_t i = 0; i < num_elements; ++i, ++it) { S_Data* element; - SerializeCaller::Run(&(*it), buf, &element, - validate_params->element_validate_params); + auto retval = SerializeCaller::Run( + &(*it), buf, &element, validate_params->element_validate_params); + if (retval != VALIDATION_ERROR_NONE) + return retval; + output->at(i) = element; - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !validate_params->element_is_nullable && !element, - VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - MakeMessageWithArrayIndex("null in array expecting valid pointers", - num_elements, i)); + if (!validate_params->element_is_nullable && !element) { + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + MakeMessageWithArrayIndex("null in array expecting valid pointers", + num_elements, i)); + return VALIDATION_ERROR_UNEXPECTED_NULL_POINTER; + } } + + return VALIDATION_ERROR_NONE; } static void DeserializeElements(Array_Data<S_Data*>* input, @@ -208,41 +230,42 @@ // takes precedence over the |String|-overloaded Run() below. template <typename T, typename = typename EnableIf<!IsSame<T, String>::value, T>::type> - static void Run(T* input, - Buffer* buf, - typename WrapperTraits<T>::DataType* output, - const ArrayValidateParams* validate_params) { + static ValidationError Run(T* input, + Buffer* buf, + typename WrapperTraits<T>::DataType* output, + const ArrayValidateParams* validate_params) { MOJO_DCHECK(!validate_params) << "Struct type should not have array validate params"; - Serialize_(UnwrapStructPtr<T>::value(*input), buf, output); + return Serialize_(UnwrapStructPtr<T>::value(*input), buf, output); } - static void Run(const String* input, - Buffer* buf, - String_Data** output, - const ArrayValidateParams* validate_params) { + static ValidationError Run(const String* input, + Buffer* buf, + String_Data** output, + const ArrayValidateParams* validate_params) { MOJO_DCHECK(validate_params && !validate_params->element_validate_params && !validate_params->element_is_nullable && validate_params->expected_num_elements == 0) << "String type has unexpected array validate params"; SerializeString_(*input, buf, output); + return VALIDATION_ERROR_NONE; } template <typename T> - static void Run(Array<T>* input, - Buffer* buf, - typename Array<T>::Data_** output, - const ArrayValidateParams* validate_params) { - SerializeArray_(input, buf, output, validate_params); + static ValidationError Run(Array<T>* input, + Buffer* buf, + typename Array<T>::Data_** output, + const ArrayValidateParams* validate_params) { + return SerializeArray_(input, buf, output, validate_params); } template <typename Key, typename Value> - static void Run(Map<Key, Value>* input, - Buffer* buf, - typename Map<Key, Value>::Data_** output, - const ArrayValidateParams* validate_params) { - SerializeMap_(input, buf, output, validate_params); + static ValidationError Run(Map<Key, Value>* input, + Buffer* buf, + typename Map<Key, Value>::Data_** output, + const ArrayValidateParams* validate_params) { + return SerializeMap_(input, buf, output, validate_params); } }; @@ -287,20 +310,28 @@ } template <typename Iterator> - static void SerializeElements(Iterator it, - size_t num_elements, - Buffer* buf, - Array_Data<U_Data>* output, - const ArrayValidateParams* validate_params) { + static ValidationError SerializeElements( + Iterator it, + size_t num_elements, + Buffer* buf, + Array_Data<U_Data>* output, + const ArrayValidateParams* validate_params) { for (size_t i = 0; i < num_elements; ++i, ++it) { U_Data* result = output->storage() + i; - SerializeUnion_(it->get(), buf, &result, true); - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - !validate_params->element_is_nullable && output->at(i).is_null(), - VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - MakeMessageWithArrayIndex("null in array expecting valid unions", - num_elements, i)); + auto retval = SerializeUnion_(it->get(), buf, &result, true); + if (retval != VALIDATION_ERROR_NONE) + return retval; + if (!validate_params->element_is_nullable && output->at(i).is_null()) { + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( + + VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, + MakeMessageWithArrayIndex("null in array expecting valid unions", + num_elements, i)); + return VALIDATION_ERROR_UNEXPECTED_NULL_POINTER; + } } + + return VALIDATION_ERROR_NONE; } static void DeserializeElements(Array_Data<U_Data>* input, Array<U>* output) { @@ -327,32 +358,43 @@ return internal::ArraySerializer<E, F>::GetSerializedSize(input); } +// SerializeArray_ will return VALIDATION_ERROR_NONE on success and set +// |output| accordingly. On failure, |input| will be partially serialized into +// |output| up until an error occurs (which is propagated up and returned by +// SerializeArray_), in which case |buf| is also partially consumed. template <typename E, typename F> -inline void SerializeArray_( +inline internal::ValidationError SerializeArray_( Array<E>* input, internal::Buffer* buf, internal::Array_Data<F>** output, const internal::ArrayValidateParams* validate_params) { MOJO_DCHECK(input); - if (*input) { + if (!*input) { + // It is up to the caller to make sure the given |Array| is not null if it + // is not nullable. + *output = nullptr; + return internal::VALIDATION_ERROR_NONE; + } + + if (validate_params->expected_num_elements != 0 && + input->size() != validate_params->expected_num_elements) { MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( - validate_params->expected_num_elements != 0 && - input->size() != validate_params->expected_num_elements, internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, internal::MakeMessageWithExpectedArraySize( "fixed-size array has wrong number of elements", input->size(), validate_params->expected_num_elements)); - - internal::Array_Data<F>* result = - internal::Array_Data<F>::New(input->size(), buf); - if (result) { - internal::ArraySerializer<E, F>::SerializeElements( - input->begin(), input->size(), buf, result, validate_params); - } - *output = result; - } else { - *output = nullptr; + return internal::ValidationError::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER; } + + internal::Array_Data<F>* result = + internal::Array_Data<F>::New(input->size(), buf); + auto retval = internal::ArraySerializer<E, F>::SerializeElements( + input->begin(), input->size(), buf, result, validate_params); + if (retval != internal::VALIDATION_ERROR_NONE) + return retval; + + *output = result; + return internal::VALIDATION_ERROR_NONE; } template <typename E, typename F>
diff --git a/mojo/public/cpp/bindings/lib/control_message_handler.cc b/mojo/public/cpp/bindings/lib/control_message_handler.cc index 0c46982..6cc9568 100644 --- a/mojo/public/cpp/bindings/lib/control_message_handler.cc +++ b/mojo/public/cpp/bindings/lib/control_message_handler.cc
@@ -56,7 +56,10 @@ ResponseMessageBuilder builder(kRunMessageId, size, message->request_id()); RunResponseMessageParams_Data* response_params = nullptr; - Serialize_(response_params_ptr.get(), builder.buffer(), &response_params); + auto result = + Serialize_(response_params_ptr.get(), builder.buffer(), &response_params); + MOJO_DCHECK(result == VALIDATION_ERROR_NONE); + response_params->EncodePointersAndHandles( builder.message()->mutable_handles()); bool ok = responder->Accept(builder.message());
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/mojo/public/cpp/bindings/lib/control_message_proxy.cc index ee1e695..c2f4594 100644 --- a/mojo/public/cpp/bindings/lib/control_message_proxy.cc +++ b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
@@ -52,7 +52,9 @@ RequestMessageBuilder builder(kRunMessageId, size); RunMessageParams_Data* params = nullptr; - Serialize_(params_ptr.get(), builder.buffer(), ¶ms); + auto result = Serialize_(params_ptr.get(), builder.buffer(), ¶ms); + MOJO_DCHECK(result == VALIDATION_ERROR_NONE); + params->EncodePointersAndHandles(builder.message()->mutable_handles()); MessageReceiver* responder = new RunResponseForwardToCallback(callback); if (!receiver->AcceptWithResponder(builder.message(), responder)) @@ -70,7 +72,9 @@ MessageBuilder builder(kRunOrClosePipeMessageId, size); RunOrClosePipeMessageParams_Data* params = nullptr; - Serialize_(params_ptr.get(), builder.buffer(), ¶ms); + auto result = Serialize_(params_ptr.get(), builder.buffer(), ¶ms); + MOJO_DCHECK(result == VALIDATION_ERROR_NONE); + params->EncodePointersAndHandles(builder.message()->mutable_handles()); bool ok = receiver->Accept(builder.message()); MOJO_ALLOW_UNUSED_LOCAL(ok);
diff --git a/mojo/public/cpp/bindings/lib/map_serialization.h b/mojo/public/cpp/bindings/lib/map_serialization.h index 8ef83b3..3f24b1a 100644 --- a/mojo/public/cpp/bindings/lib/map_serialization.h +++ b/mojo/public/cpp/bindings/lib/map_serialization.h
@@ -121,6 +121,11 @@ value_data_size; } +// SerializeMap_ will return VALIDATION_ERROR_NONE on success and set +// |output| accordingly. On failure, |input| will be partially serialized into +// |output| up until an error occurs (which is propagated up and returned by +// SerializeMap_), in which case |buf| is also partially consumed. +// // We don't need an ArrayValidateParams instance for key validation since // we can deduce it from the Key type. (which can only be primitive types or // non-nullable strings.) @@ -128,45 +133,54 @@ typename MapValue, typename DataKey, typename DataValue> -inline void SerializeMap_( +inline internal::ValidationError SerializeMap_( Map<MapKey, MapValue>* input, internal::Buffer* buf, internal::Map_Data<DataKey, DataValue>** output, const internal::ArrayValidateParams* value_validate_params) { - if (input && *input) { - internal::Map_Data<DataKey, DataValue>* result = - internal::Map_Data<DataKey, DataValue>::New(buf); - internal::Array_Data<DataKey>* keys_data = - internal::Array_Data<DataKey>::New(input->size(), buf); + if (input->is_null()) { + // |input| could be a nullable map, in which case |output| is serialized as + // null, which is valid. + *output = nullptr; + return internal::VALIDATION_ERROR_NONE; + } - if (result && keys_data) { - result->keys.ptr = keys_data; + internal::Map_Data<DataKey, DataValue>* result = + internal::Map_Data<DataKey, DataValue>::New(buf); - // We *must* serialize the keys before we allocate an Array_Data for the - // values. - internal::MapKeyIterator<MapKey, MapValue> key_iter(input); - const internal::ArrayValidateParams* key_validate_params = - internal::MapKeyValidateParamsFactory<DataKey>::Get(); + // We *must* serialize the keys before we allocate an Array_Data for the + // values. + internal::Array_Data<DataKey>* keys_data = + internal::Array_Data<DataKey>::New(input->size(), buf); + result->keys.ptr = keys_data; + internal::MapKeyIterator<MapKey, MapValue> key_iter(input); + const internal::ArrayValidateParams* key_validate_params = + internal::MapKeyValidateParamsFactory<DataKey>::Get(); + + auto keys_retval = internal::ArraySerializer<MapKey, DataKey>::SerializeElements( key_iter.begin(), input->size(), buf, result->keys.ptr, key_validate_params); + if (keys_retval != internal::VALIDATION_ERROR_NONE) + return keys_retval; - // Now we try allocate an Array_Data for the values - internal::Array_Data<DataValue>* values_data = - internal::Array_Data<DataValue>::New(input->size(), buf); - if (values_data) { - result->values.ptr = values_data; - internal::MapValueIterator<MapKey, MapValue> value_iter(input); - internal::ArraySerializer<MapValue, DataValue>::SerializeElements( - value_iter.begin(), input->size(), buf, result->values.ptr, - value_validate_params); - } - } - *output = result; - } else { - *output = nullptr; - } + // Now we try allocate an Array_Data for the values + internal::Array_Data<DataValue>* values_data = + internal::Array_Data<DataValue>::New(input->size(), buf); + result->values.ptr = values_data; + + internal::MapValueIterator<MapKey, MapValue> value_iter(input); + + auto values_retval = + internal::ArraySerializer<MapValue, DataValue>::SerializeElements( + value_iter.begin(), input->size(), buf, result->values.ptr, + value_validate_params); + if (values_retval != internal::VALIDATION_ERROR_NONE) + return values_retval; + + *output = result; + return internal::VALIDATION_ERROR_NONE; } template <typename MapKey,
diff --git a/mojo/public/cpp/bindings/lib/map_serialization_forward.h b/mojo/public/cpp/bindings/lib/map_serialization_forward.h index 40f6e8e..e6cd69f 100644 --- a/mojo/public/cpp/bindings/lib/map_serialization_forward.h +++ b/mojo/public/cpp/bindings/lib/map_serialization_forward.h
@@ -26,10 +26,11 @@ typename MapValue, typename DataKey, typename DataValue> -void SerializeMap_(Map<MapKey, MapValue>* input, - internal::Buffer* buf, - internal::Map_Data<DataKey, DataValue>** output, - const internal::ArrayValidateParams* value_validate_params); +internal::ValidationError SerializeMap_( + Map<MapKey, MapValue>* input, + internal::Buffer* buf, + internal::Map_Data<DataKey, DataValue>** output, + const internal::ArrayValidateParams* value_validate_params); template <typename MapKey, typename MapValue> size_t GetSerializedSize_(const Map<MapKey, MapValue>& input);
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc index aa5f97a..4137ba1 100644 --- a/mojo/public/cpp/bindings/lib/validation_errors.cc +++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -11,8 +11,6 @@ namespace { ValidationErrorObserverForTesting* g_validation_error_observer = nullptr; -SerializationWarningObserverForTesting* g_serialization_warning_observer = - nullptr; } // namespace @@ -73,26 +71,5 @@ g_validation_error_observer = nullptr; } -bool ReportSerializationWarning(ValidationError error) { - if (g_serialization_warning_observer) { - g_serialization_warning_observer->set_last_warning(error); - return true; - } - - return false; -} - -SerializationWarningObserverForTesting::SerializationWarningObserverForTesting() - : last_warning_(VALIDATION_ERROR_NONE) { - MOJO_DCHECK(!g_serialization_warning_observer); - g_serialization_warning_observer = this; -} - -SerializationWarningObserverForTesting:: - ~SerializationWarningObserverForTesting() { - MOJO_DCHECK(g_serialization_warning_observer == this); - g_serialization_warning_observer = nullptr; -} - } // namespace internal } // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.h b/mojo/public/cpp/bindings/lib/validation_errors.h index 43059c2..953ab5e 100644 --- a/mojo/public/cpp/bindings/lib/validation_errors.h +++ b/mojo/public/cpp/bindings/lib/validation_errors.h
@@ -78,45 +78,13 @@ MOJO_DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting); }; -// Used only by MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING. Don't use it directly. -// -// The function returns true if the error is recorded (by a -// SerializationWarningObserverForTesting object), false otherwise. -bool ReportSerializationWarning(ValidationError error); - -// Only used by serialization tests and when there is only one thread doing -// message serialization. -class SerializationWarningObserverForTesting { - public: - SerializationWarningObserverForTesting(); - ~SerializationWarningObserverForTesting(); - - ValidationError last_warning() const { return last_warning_; } - void set_last_warning(ValidationError error) { last_warning_ = error; } - - private: - ValidationError last_warning_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(SerializationWarningObserverForTesting); -}; - } // namespace internal } // namespace mojo -// In debug build, logs a serialization warning if |condition| evaluates to -// true: -// - if there is a SerializationWarningObserverForTesting object alive, -// records |error| in it; -// - otherwise, logs a fatal-level message. -// |error| is the validation error that will be triggered by the receiver -// of the serialzation result. -// -// In non-debug build, does nothing (not even compiling |condition|). -#define MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( \ - condition, error, description) \ - MOJO_DLOG_IF(FATAL, (condition) && !ReportSerializationWarning(error)) \ - << "The outgoing message will trigger " \ - << ValidationErrorToString(error) << " at the receiving side (" \ - << description << ")."; +// In a debug build, logs a serialization warning. +#define MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(error, description) \ + MOJO_DLOG(WARNING) << "The outgoing message will trigger " \ + << ValidationErrorToString(error) \ + << " at the receiving side (" << description << ")." #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
diff --git a/mojo/public/cpp/bindings/tests/array_unittest.cc b/mojo/public/cpp/bindings/tests/array_unittest.cc index ffee9cc..3eecd52 100644 --- a/mojo/public/cpp/bindings/tests/array_unittest.cc +++ b/mojo/public/cpp/bindings/tests/array_unittest.cc
@@ -161,7 +161,8 @@ FixedBufferForTesting buf(size); Array_Data<int32_t>* data; ArrayValidateParams validate_params(0, false, nullptr); - SerializeArray_(&array, &buf, &data, &validate_params); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + SerializeArray_(&array, &buf, &data, &validate_params)); Array<int32_t> array2; Deserialize_(data, &array2); @@ -179,7 +180,8 @@ FixedBufferForTesting buf(size); Array_Data<int32_t>* data; ArrayValidateParams validate_params(0, false, nullptr); - SerializeArray_(&array, &buf, &data, &validate_params); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + SerializeArray_(&array, &buf, &data, &validate_params)); Array<int32_t> array2; Deserialize_(data, &array2); @@ -202,7 +204,8 @@ Array_Data<Array_Data<int32_t>*>* data; ArrayValidateParams validate_params( 0, false, new ArrayValidateParams(0, false, nullptr)); - SerializeArray_(&array, &buf, &data, &validate_params); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + SerializeArray_(&array, &buf, &data, &validate_params)); Array<Array<int32_t>> array2; Deserialize_(data, &array2); @@ -227,7 +230,8 @@ FixedBufferForTesting buf(size); Array_Data<bool>* data; ArrayValidateParams validate_params(0, false, nullptr); - SerializeArray_(&array, &buf, &data, &validate_params); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + SerializeArray_(&array, &buf, &data, &validate_params)); Array<bool> array2; Deserialize_(data, &array2); @@ -255,7 +259,8 @@ Array_Data<String_Data*>* data; ArrayValidateParams validate_params( 0, false, new ArrayValidateParams(0, false, nullptr)); - SerializeArray_(&array, &buf, &data, &validate_params); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + SerializeArray_(&array, &buf, &data, &validate_params)); Array<String> array2; Deserialize_(data, &array2);
diff --git a/mojo/public/cpp/bindings/tests/map_unittest.cc b/mojo/public/cpp/bindings/tests/map_unittest.cc index 9a15253..499a67b 100644 --- a/mojo/public/cpp/bindings/tests/map_unittest.cc +++ b/mojo/public/cpp/bindings/tests/map_unittest.cc
@@ -246,7 +246,8 @@ Array_Data<Map_Data<int32_t, int8_t>*>* data; ArrayValidateParams validate_params( 0, false, new ArrayValidateParams(0, false, nullptr)); - SerializeArray_(&array, &buf, &data, &validate_params); + EXPECT_EQ(internal::VALIDATION_ERROR_NONE, + SerializeArray_(&array, &buf, &data, &validate_params)); Array<Map<int32_t, int8_t>> deserialized_array; Deserialize_(data, &deserialized_array); @@ -269,7 +270,8 @@ ArrayValidateParams validate_params( 0, false, new ArrayValidateParams( 0, false, new ArrayValidateParams(0, false, nullptr))); - SerializeArray_(&array, &buf, &data, &validate_params); + EXPECT_EQ(internal::VALIDATION_ERROR_NONE, + SerializeArray_(&array, &buf, &data, &validate_params)); Array<Map<String, Array<bool>>> deserialized_array; Deserialize_(data, &deserialized_array);
diff --git a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc index b61d3bc..85b0924 100644 --- a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc +++ b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc
@@ -57,29 +57,21 @@ template <typename T, typename TPtr> void TestStructWarningImpl(TPtr obj, mojo::internal::ValidationError expected_warning) { - warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); - mojo::internal::FixedBufferForTesting buf(GetSerializedSize_(*obj)); typename T::Data_* data; - Serialize_(obj.get(), &buf, &data); - - EXPECT_EQ(expected_warning, warning_observer_.last_warning()); + EXPECT_EQ(expected_warning, Serialize_(obj.get(), &buf, &data)); } template <typename T> void TestArrayWarning(T obj, mojo::internal::ValidationError expected_warning, const ArrayValidateParams* validate_params) { - warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); - mojo::internal::FixedBufferForTesting buf(GetSerializedSize_(obj)); typename T::Data_* data; - SerializeArray_(&obj, &buf, &data, validate_params); - - EXPECT_EQ(expected_warning, warning_observer_.last_warning()); + EXPECT_EQ(expected_warning, + SerializeArray_(&obj, &buf, &data, validate_params)); } - mojo::internal::SerializationWarningObserverForTesting warning_observer_; Environment env_; };
diff --git a/mojo/public/cpp/bindings/tests/struct_unittest.cc b/mojo/public/cpp/bindings/tests/struct_unittest.cc index 283dd8e..8a3dadf 100644 --- a/mojo/public/cpp/bindings/tests/struct_unittest.cc +++ b/mojo/public/cpp/bindings/tests/struct_unittest.cc
@@ -5,6 +5,7 @@ #include <string.h> #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" +#include "mojo/public/cpp/bindings/lib/validation_errors.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/system/message_pipe.h" #include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h" @@ -54,7 +55,8 @@ size_t size = GetSerializedSize_(*input); mojo::internal::FixedBufferForTesting buf(size + 32); InputDataType data; - Serialize_(input.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(input.get(), &buf, &data)); std::vector<Handle> handles; data->EncodePointersAndHandles(&handles); @@ -144,7 +146,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::Rect_Data* data; - Serialize_(rect.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(rect.get(), &buf, &data)); RectPtr rect2(Rect::New()); Deserialize_(data, rect2.get()); @@ -177,7 +180,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::RectPair_Data* data; - Serialize_(pair.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(pair.get(), &buf, &data)); RectPairPtr pair2(RectPair::New()); Deserialize_(data, pair2.get()); @@ -208,7 +212,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::NamedRegion_Data* data; - Serialize_(region.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(region.get(), &buf, &data)); NamedRegionPtr region2(NamedRegion::New()); Deserialize_(data, region2.get()); @@ -234,7 +239,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::NamedRegion_Data* data; - Serialize_(region.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(region.get(), &buf, &data)); NamedRegionPtr region2(NamedRegion::New()); Deserialize_(data, region2.get());
diff --git a/mojo/public/cpp/bindings/tests/union_unittest.cc b/mojo/public/cpp/bindings/tests/union_unittest.cc index 4df0f21..afeb4a5 100644 --- a/mojo/public/cpp/bindings/tests/union_unittest.cc +++ b/mojo/public/cpp/bindings/tests/union_unittest.cc
@@ -501,7 +501,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::SmallStruct_Data* data = nullptr; - Serialize_(small_struct.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(small_struct.get(), &buf, &data)); SmallStructPtr deserialized(SmallStruct::New()); Deserialize_(data, deserialized.get()); @@ -521,7 +522,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::SmallObjStruct_Data* data = nullptr; - Serialize_(obj_struct.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(obj_struct.get(), &buf, &data)); std::vector<Handle> handles; data->EncodePointersAndHandles(&handles); @@ -544,7 +546,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::SmallStruct_Data* data = nullptr; - Serialize_(small_struct.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(small_struct.get(), &buf, &data)); std::vector<Handle> handles; data->EncodePointersAndHandles(&handles); @@ -568,7 +571,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::SmallStruct_Data* data = nullptr; - Serialize_(small_struct.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(small_struct.get(), &buf, &data)); data->pod_union.tag = static_cast<internal::PodUnion_Data::PodUnion_Tag>(100); std::vector<Handle> handles; @@ -611,7 +615,8 @@ mojo::internal::FixedBufferForTesting buf(size); internal::SmallStruct_Data* data = nullptr; - Serialize_(small_struct.get(), &buf, &data); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + Serialize_(small_struct.get(), &buf, &data)); std::vector<Handle> handles; data->EncodePointersAndHandles(&handles); @@ -655,7 +660,8 @@ mojo::internal::Map_Data<mojo::internal::String_Data*, internal::PodUnion_Data>* data; mojo::internal::ArrayValidateParams validate_params(0, false, nullptr); - SerializeMap_(&map, &buf, &data, &validate_params); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + SerializeMap_(&map, &buf, &data, &validate_params)); Map<String, PodUnionPtr> map2; Deserialize_(data, &map2); @@ -679,7 +685,8 @@ mojo::internal::Map_Data<mojo::internal::String_Data*, internal::PodUnion_Data>* data; mojo::internal::ArrayValidateParams validate_params(0, true, nullptr); - SerializeMap_(&map, &buf, &data, &validate_params); + EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE, + SerializeMap_(&map, &buf, &data, &validate_params)); Map<String, PodUnionPtr> map2; Deserialize_(data, &map2);
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl index e428704..a8fcdba 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -26,7 +26,7 @@ {%- endmacro %} {%- macro build_message(struct, struct_display_name) -%} - {{struct_macros.serialize(struct, struct_display_name, "in_%s", "params", "builder.buffer()")}} + {{struct_macros.serialize(struct, struct_display_name, "in_%s", "params", "builder.buffer()", false)}} params->EncodePointersAndHandles(builder.message()->mutable_handles()); {%- endmacro %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl index b38bd45..cde243f 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -26,6 +26,88 @@ {%- endfor %} {%- endmacro -%} +{# A private macro that prints the C++ log-and-report serialization errors + macro, and conditionally returns if |should_return_errors| #} +{%- macro _validation_check_macro(condition, error_code, error_msg, should_return_errors=false) -%} + if ({{condition}}) { + MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING({{error_code}}, "{{error_msg}}"); + {%- if should_return_errors %} + return {{error_code}}; + {%- endif %} + } +{%- endmacro -%} + +{# The following 4 macros call |SerializeArray_|, |SerializeMap_|, + |SerializeUnion_| and |Serialize_| respectively. If |should_return_error| + is true, these macros do the extra work of propagating non-successful error + codes. #} +{%- macro call_serialize_array(name, kind, input, buffer, output, + should_return_errors, indent_size) -%} + { + const mojo::internal::ArrayValidateParams {{name}}_validate_params( + {{kind|get_array_validate_params_ctor_args|indent(indent_size)}}); +{%- if should_return_errors -%} + auto retval = +{%- endif -%} + mojo::SerializeArray_({{input}}, {{buffer}}, {{output}}, + &{{name}}_validate_params); +{%- if should_return_errors %} + if (retval != mojo::internal::VALIDATION_ERROR_NONE) + return retval; +{%- endif %} + } +{%- endmacro -%} + +{%- macro call_serialize_map(name, kind, input, buffer, output, + should_return_errors, indent_size) -%} + { + const mojo::internal::ArrayValidateParams {{name}}_validate_params( + {{kind.value_kind|get_map_validate_params_ctor_args|indent(indent_size)}}); +{%- if should_return_errors -%} + auto retval = +{%- endif -%} + mojo::SerializeMap_( + {{input}}, {{buffer}}, {{output}}, + &{{name}}_validate_params); +{%- if should_return_errors %} + if (retval != mojo::internal::VALIDATION_ERROR_NONE) + return retval; +{%- endif %} + } +{%- endmacro -%} + +{%- macro call_serialize_union(input, buffer, output, inlined, + should_return_errors) -%} + { +{%- if should_return_errors -%} + auto retval = +{%- endif -%} + SerializeUnion_({{input}}, + {{buffer}}, + {{output}}, + {{inlined}}); +{%- if should_return_errors %} + if (retval != mojo::internal::VALIDATION_ERROR_NONE) + return retval; +{%- endif %} + } +{%- endmacro -%} + +{%- macro call_serialize_struct(input, buffer, output, should_return_errors) -%} + { +{%- if should_return_errors -%} + auto retval = +{%- endif -%} + Serialize_({{input}}, + {{buffer}}, + {{output}}); +{%- if should_return_errors %} + if (retval != mojo::internal::VALIDATION_ERROR_NONE) + return retval; +{%- endif %} + } +{%- endmacro -%} + {# Serializes the specified struct. |struct| is the struct definition. |struct_display_name| is the display name for the struct that can be showed @@ -35,12 +117,18 @@ substituted with struct field names to refer to the input fields. |output| is the name of the output struct instance. |buffer| is the name of the Buffer instance used. + |should_return_errors| is true if validation errors need to be return'd. + This is needed when serializing interface parameters, where you cannot + return. + This macro is expanded to do serialization for both: - user-defined structs: the input is an instance of the corresponding struct wrapper class. - method parameters/response parameters: the input is a list of - arguments. #} -{%- macro serialize(struct, struct_display_name, input_field_pattern, output, buffer) -%} + arguments. + This macro is expanded within the C++ struct serialization methods #} +{%- macro serialize(struct, struct_display_name, input_field_pattern, + output, buffer, should_return_errors=false) -%} internal::{{struct.name}}_Data* {{output}} = internal::{{struct.name}}_Data::New({{buffer}}); {%- for pf in struct.packed.packed_fields_in_ordinal_order %} @@ -49,33 +137,47 @@ {%- set kind = pf.field.kind %} {%- if kind|is_object_kind %} {%- if kind|is_array_kind %} - const mojo::internal::ArrayValidateParams {{name}}_validate_params( - {{kind|get_array_validate_params_ctor_args|indent(10)}}); - mojo::SerializeArray_(&{{input_field}}, {{buffer}}, - &{{output}}->{{name}}.ptr, &{{name}}_validate_params); + {{call_serialize_array(name = name, + kind = kind, + input = '&' ~ input_field, + buffer = buffer, + output = "&%s->%s.ptr"|format(output,name), + should_return_errors = should_return_errors, + indent_size = 10)}} {%- elif kind|is_map_kind %} - const mojo::internal::ArrayValidateParams {{name}}_validate_params( - {{kind.value_kind|get_map_validate_params_ctor_args|indent(10)}}); - mojo::SerializeMap_( - &{{input_field}}, {{buffer}}, &{{output}}->{{name}}.ptr, - &{{name}}_validate_params); + {{call_serialize_map(name = name, + kind = kind, + input = '&' ~ input_field, + buffer = buffer, + output = '&%s->%s.ptr'|format(output,name), + should_return_errors = should_return_errors, + indent_size = 10)}} {%- elif kind|is_union_kind %} internal::{{kind.name}}_Data* {{name}}_ptr = &{{output}}->{{name}}; - SerializeUnion_({{input_field}}.get(), {{buffer}}, &{{name}}_ptr, true); + {{call_serialize_union(input = input_field ~ ".get()", + buffer = buffer, + output = "&%s_ptr"|format(name), + inlined = "true", + should_return_errors = should_return_errors)}} {%- elif kind|is_string_kind %} SerializeString_({{input_field}}, {{buffer}}, &{{output}}->{{name}}.ptr); {%- else %} - Serialize_({{input_field}}.get(), {{buffer}}, &{{output}}->{{name}}.ptr); + {{call_serialize_struct(input = input_field ~ ".get()", + buffer = buffer, + output = "&%s->%s.ptr"|format(output,name), + should_return_errors = should_return_errors)}} {%- endif %} {%- if not kind|is_nullable_kind %} - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( {%- if kind|is_union_kind %} - {{output}}->{{name}}.is_null(), +{%- set condition = "%s->%s.is_null()" | format(output, name) %} {%- else %} - !{{output}}->{{name}}.ptr, +{%- set condition = "!%s->%s.ptr" | format(output,name) %} {%- endif %} - mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, - "null {{name}} in {{struct_display_name}}"); + {{_validation_check_macro( + condition = condition, + error_code = "mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER", + error_msg = "null %s in %s" | format(name, struct_display_name), + should_return_errors = should_return_errors)}} {%- endif %} {%- elif kind|is_any_handle_kind or kind|is_interface_kind %} {%- if kind|is_interface_kind %} @@ -86,14 +188,16 @@ {{output}}->{{name}} = {{input_field}}.release(); {%- endif %} {%- if not kind|is_nullable_kind %} - MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING( {%- if kind|is_interface_kind %} - !{{output}}->{{name}}.handle.is_valid(), +{%- set condition = "!%s->%s.handle.is_valid()" | format(output, name) %} {%- else %} - !{{output}}->{{name}}.is_valid(), +{%- set condition = "!%s->%s.is_valid()" | format(output,name) %} {%- endif %} - mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, - "invalid {{name}} in {{struct_display_name}}"); + {{_validation_check_macro( + condition = condition, + error_code = "mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE", + error_msg = "invalid %s in %s" | format(name, struct_display_name), + should_return_errors = should_return_errors)}} {%- endif %} {%- elif kind|is_enum_kind %} {{output}}->{{name}} =
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl index 6243372..84534fd 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
@@ -1,5 +1,7 @@ size_t GetSerializedSize_(const {{struct.name}}& input); -void Serialize_({{struct.name}}* input, mojo::internal::Buffer* buffer, - internal::{{struct.name}}_Data** output); +mojo::internal::ValidationError Serialize_( + {{struct.name}}* input, + mojo::internal::Buffer* buffer, + internal::{{struct.name}}_Data** output); void Deserialize_(internal::{{struct.name}}_Data* input, {{struct.name}}* output); \ No newline at end of file
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl index eb6fcec..752795b 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl
@@ -4,14 +4,17 @@ return size; } -void Serialize_({{struct.name}}* input, mojo::internal::Buffer* buf, - internal::{{struct.name}}_Data** output) { +mojo::internal::ValidationError Serialize_( + {{struct.name}}* input, + mojo::internal::Buffer* buf, + internal::{{struct.name}}_Data** output) { if (input) { - {{struct_macros.serialize(struct, struct.name ~ " struct", "input->%s", "result", "buf")|indent(2)}} + {{struct_macros.serialize(struct, struct.name ~ " struct", "input->%s", "result", "buf", true)|indent(2)}} *output = result; } else { *output = nullptr; } + return mojo::internal::VALIDATION_ERROR_NONE; } void Deserialize_(internal::{{struct.name}}_Data* input,
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl index 588e749..d29a356 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
@@ -1,5 +1,7 @@ size_t GetSerializedSize_(const {{union.name}}Ptr& input, bool inlined); -void SerializeUnion_({{union.name}}* input, mojo::internal::Buffer* buffer, - internal::{{union.name}}_Data** output, bool inlined); +mojo::internal::ValidationError SerializeUnion_( + {{union.name}}* input, + mojo::internal::Buffer* buffer, + internal::{{union.name}}_Data** output, bool inlined); void Deserialize_(internal::{{union.name}}_Data* input, {{union.name}}* output); \ No newline at end of file
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl index 4acbeb2..c0fa566 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
@@ -1,3 +1,4 @@ +{% import 'struct_macros.tmpl' as struct_macros without context %} size_t GetSerializedSize_(const {{union.name}}Ptr& input, bool inlined) { size_t size = 0U; if (!inlined) { @@ -28,8 +29,11 @@ return size; } -void SerializeUnion_({{union.name}}* input, mojo::internal::Buffer* buf, - internal::{{union.name}}_Data** output, bool inlined) { +mojo::internal::ValidationError SerializeUnion_( + {{union.name}}* input, + mojo::internal::Buffer* buf, + internal::{{union.name}}_Data** output, + bool inlined) { internal::{{union.name}}_Data* result = *output; if (input) { if (!inlined) { @@ -49,25 +53,36 @@ *input_acc.data()->{{field.name}}, buf, &result->data.f_{{field.name}}.ptr); {% elif field.kind|is_struct_kind %} - Serialize_( - input_acc.data()->{{field.name}}->get(), - buf, &result->data.f_{{field.name}}.ptr); + {{struct_macros.call_serialize_struct( + input = "input_acc.data()->%s->get()"|format(field.name), + buffer = "buf", + output = "&result->data.f_%s.ptr"|format(field.name), + should_return_errors = true)|indent(6)}} {% elif field.kind|is_union_kind %} - SerializeUnion_( - input_acc.data()->{{field.name}}->get(), - buf, &result->data.f_{{field.name}}.ptr, false); + {{struct_macros.call_serialize_union( + input = "input_acc.data()->%s->get()"|format(field.name), + buffer = "buf", + output = "&result->data.f_%s.ptr"|format(field.name), + inlined = "false", + should_return_errors = true)|indent(6)}} {% elif field.kind|is_array_kind %} - const mojo::internal::ArrayValidateParams {{field.name}}_validate_params( - {{field.kind|get_array_validate_params_ctor_args|indent(16)}}); - SerializeArray_( - input_acc.data()->{{field.name}}, - buf, &result->data.f_{{field.name}}.ptr, &{{field.name}}_validate_params); + {{struct_macros.call_serialize_array( + name = field.name, + kind = field.kind, + input = "input_acc.data()->%s"|format(field.name), + buffer = "buf", + output = "&result->data.f_%s.ptr"|format(field.name), + should_return_errors = true, + indent_size = 16)|indent(6)}} {% elif field.kind|is_map_kind %} - const mojo::internal::ArrayValidateParams {{field.name}}_validate_params( - {{field.kind.value_kind|get_map_validate_params_ctor_args|indent(16)}}); - SerializeMap_( - input_acc.data()->{{field.name}}, - buf, &result->data.f_{{field.name}}.ptr, &{{field.name}}_validate_params); + {{struct_macros.call_serialize_map( + name = field.name, + kind = field.kind, + input = "input_acc.data()->%s"|format(field.name), + buffer = "buf", + output = "&result->data.f_%s.ptr"|format(field.name), + should_return_errors = true, + indent_size = 16)|indent(6)}} {%- endif %} {% elif field.kind|is_any_handle_kind %} result->data.f_{{field.name}} = @@ -88,6 +103,7 @@ } {%- endfor %} default: + // TODO(vardhan): Should this return an error code instead? MOJO_CHECK(false) << "No sane way to serialize a union with an unknown tag."; break; } @@ -97,6 +113,7 @@ result = nullptr; } *output = result; + return mojo::internal::VALIDATION_ERROR_NONE; } void Deserialize_(internal::{{union.name}}_Data* input,