Commit 1e0b95af authored by qsr's avatar qsr Committed by Commit bot

mojo: Allow circular dependencies between structs

This fix the C++ and python generation to allow circular dependencies
between structs.

R=viettrungluu@chromium.org

Review URL: https://codereview.chromium.org/622593002

Cr-Commit-Position: refs/heads/master@{#299079}
parent 9a09162a
...@@ -132,12 +132,20 @@ struct ArraySerializer<ScopedHandleBase<H>, H, true> { ...@@ -132,12 +132,20 @@ struct ArraySerializer<ScopedHandleBase<H>, H, true> {
} }
}; };
// This template must only apply to pointer mojo entity (structs and arrays).
// This is done by ensuring that WrapperTraits<S>::DataType is a pointer.
template <typename S> template <typename S>
struct ArraySerializer<S, typename S::Data_*, true> { struct ArraySerializer<S,
typename internal::EnableIf<
internal::IsPointer<typename internal::WrapperTraits<
S>::DataType>::value,
typename internal::WrapperTraits<S>::DataType>::type,
true> {
typedef typename internal::RemovePointer<
typename internal::WrapperTraits<S>::DataType>::type S_Data;
static size_t GetSerializedSize(const Array<S>& input) { static size_t GetSerializedSize(const Array<S>& input) {
size_t size = size_t size = sizeof(Array_Data<S_Data*>) +
sizeof(Array_Data<typename S::Data_*>) + input.size() * sizeof(internal::StructPointer<S_Data>);
input.size() * sizeof(internal::StructPointer<typename S::Data_>);
for (size_t i = 0; i < input.size(); ++i) for (size_t i = 0; i < input.size(); ++i)
size += GetSerializedSize_(input[i]); size += GetSerializedSize_(input[i]);
return size; return size;
...@@ -145,9 +153,9 @@ struct ArraySerializer<S, typename S::Data_*, true> { ...@@ -145,9 +153,9 @@ struct ArraySerializer<S, typename S::Data_*, true> {
template <bool element_is_nullable, typename ElementValidateParams> template <bool element_is_nullable, typename ElementValidateParams>
static void SerializeElements(Array<S> input, static void SerializeElements(Array<S> input,
Buffer* buf, Buffer* buf,
Array_Data<typename S::Data_*>* output) { Array_Data<S_Data*>* output) {
for (size_t i = 0; i < input.size(); ++i) { for (size_t i = 0; i < input.size(); ++i) {
typename S::Data_* element; S_Data* element;
SerializeCaller<S, ElementValidateParams>::Run( SerializeCaller<S, ElementValidateParams>::Run(
input[i].Pass(), buf, &element); input[i].Pass(), buf, &element);
output->at(i) = element; output->at(i) = element;
...@@ -158,7 +166,7 @@ struct ArraySerializer<S, typename S::Data_*, true> { ...@@ -158,7 +166,7 @@ struct ArraySerializer<S, typename S::Data_*, true> {
"null in array expecting valid pointers", input.size(), i)); "null in array expecting valid pointers", input.size(), i));
} }
} }
static void DeserializeElements(Array_Data<typename S::Data_*>* input, static void DeserializeElements(Array_Data<S_Data*>* input,
Array<S>* output) { Array<S>* output) {
Array<S> result(input->size()); Array<S> result(input->size());
for (size_t i = 0; i < input->size(); ++i) { for (size_t i = 0; i < input->size(); ++i) {
...@@ -172,7 +180,9 @@ struct ArraySerializer<S, typename S::Data_*, true> { ...@@ -172,7 +180,9 @@ struct ArraySerializer<S, typename S::Data_*, true> {
private: private:
template <typename T, typename Params> template <typename T, typename Params>
struct SerializeCaller { struct SerializeCaller {
static void Run(T input, Buffer* buf, typename T::Data_** output) { static void Run(T input,
Buffer* buf,
typename internal::WrapperTraits<T>::DataType* output) {
static_assert((IsSame<Params, NoValidateParams>::value), static_assert((IsSame<Params, NoValidateParams>::value),
"Struct type should not have array validate params"); "Struct type should not have array validate params");
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_H_
#include "mojo/public/cpp/bindings/lib/template_util.h" #include "mojo/public/cpp/bindings/lib/template_util.h"
#include "mojo/public/cpp/bindings/struct_ptr.h"
#include "mojo/public/cpp/system/core.h" #include "mojo/public/cpp/system/core.h"
namespace mojo { namespace mojo {
...@@ -81,6 +82,14 @@ struct WrapperTraits<ScopedHandleBase<H>, true> { ...@@ -81,6 +82,14 @@ struct WrapperTraits<ScopedHandleBase<H>, true> {
typedef H DataType; typedef H DataType;
}; };
template <typename S> template <typename S>
struct WrapperTraits<StructPtr<S>, true> {
typedef typename S::Data_* DataType;
};
template <typename S>
struct WrapperTraits<InlinedStructPtr<S>, true> {
typedef typename S::Data_* DataType;
};
template <typename S>
struct WrapperTraits<S, true> { struct WrapperTraits<S, true> {
typedef typename S::Data_* DataType; typedef typename S::Data_* DataType;
}; };
......
...@@ -24,6 +24,11 @@ struct IsConst : FalseType {}; ...@@ -24,6 +24,11 @@ struct IsConst : FalseType {};
template <class T> template <class T>
struct IsConst<const T> : TrueType {}; struct IsConst<const T> : TrueType {};
template <class T>
struct IsPointer : FalseType {};
template <class T>
struct IsPointer<T*> : TrueType {};
template <bool B, typename T = void> template <bool B, typename T = void>
struct EnableIf {}; struct EnableIf {};
...@@ -92,6 +97,13 @@ struct IsBaseOf { ...@@ -92,6 +97,13 @@ struct IsBaseOf {
!IsSame<Base const, void const>::value; !IsSame<Base const, void const>::value;
}; };
template <class T>
struct RemovePointer {};
template <class T>
struct RemovePointer<T*> {
typedef T type;
};
} // namespace internal } // namespace internal
} // namespace mojo } // namespace mojo
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <new> #include <new>
#include "mojo/public/cpp/bindings/type_converter.h"
#include "mojo/public/cpp/environment/logging.h" #include "mojo/public/cpp/environment/logging.h"
#include "mojo/public/cpp/system/macros.h" #include "mojo/public/cpp/system/macros.h"
...@@ -29,7 +30,6 @@ class StructPtr { ...@@ -29,7 +30,6 @@ class StructPtr {
MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(StructPtr, RValue); MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(StructPtr, RValue);
public: public:
typedef typename Struct::Data_ Data_;
StructPtr() : ptr_(nullptr) {} StructPtr() : ptr_(nullptr) {}
~StructPtr() { delete ptr_; } ~StructPtr() { delete ptr_; }
...@@ -98,7 +98,6 @@ class InlinedStructPtr { ...@@ -98,7 +98,6 @@ class InlinedStructPtr {
MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InlinedStructPtr, RValue); MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InlinedStructPtr, RValue);
public: public:
typedef typename Struct::Data_ Data_;
InlinedStructPtr() : is_null_(true) {} InlinedStructPtr() : is_null_(true) {}
~InlinedStructPtr() {} ~InlinedStructPtr() {}
......
...@@ -44,7 +44,8 @@ class SerializationWarningTest : public testing::Test { ...@@ -44,7 +44,8 @@ class SerializationWarningTest : public testing::Test {
protected: protected:
template <typename T> template <typename T>
void TestWarning(T obj, mojo::internal::ValidationError expected_warning) { void TestWarning(StructPtr<T> obj,
mojo::internal::ValidationError expected_warning) {
warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE);
mojo::internal::FixedBuffer buf(GetSerializedSize_(obj)); mojo::internal::FixedBuffer buf(GetSerializedSize_(obj));
......
...@@ -34,4 +34,23 @@ enum EnumWithK { ...@@ -34,4 +34,23 @@ enum EnumWithK {
K = 0 K = 0
}; };
struct Edge {
Vertex? v;
};
struct Vertex {
EmptyStruct? e;
};
struct EmptyStruct {
};
struct A {
B? b;
};
struct B {
A? a;
};
} // module imported } // module imported
...@@ -372,11 +372,18 @@ class NativeArrayType(BaseArrayType): ...@@ -372,11 +372,18 @@ class NativeArrayType(BaseArrayType):
class StructType(PointerType): class StructType(PointerType):
"""Type object for structs.""" """Type object for structs."""
def __init__(self, struct_type, nullable=False): def __init__(self, struct_type_getter, nullable=False):
PointerType.__init__(self) PointerType.__init__(self)
self.struct_type = struct_type self._struct_type_getter = struct_type_getter
self._struct_type = None
self.nullable = nullable self.nullable = nullable
@property
def struct_type(self):
if not self._struct_type:
self._struct_type = self._struct_type_getter()
return self._struct_type
def Convert(self, value): def Convert(self, value):
if value is None or isinstance(value, self.struct_type): if value is None or isinstance(value, self.struct_type):
return value return value
......
...@@ -32,6 +32,11 @@ class {{struct.name}}; ...@@ -32,6 +32,11 @@ class {{struct.name}};
namespace internal { namespace internal {
{#--- Internal forward declarations #}
{% for struct in structs %}
class {{struct.name}}_Data;
{%- endfor %}
#pragma pack(push, 1) #pragma pack(push, 1)
{#--- Class declarations #} {#--- Class declarations #}
......
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
{{kind.value_kind|get_map_validate_params|indent(10)}}>( {{kind.value_kind|get_map_validate_params|indent(10)}}>(
mojo::internal::DecodePointerRaw(&object->{{name}}.offset), mojo::internal::DecodePointerRaw(&object->{{name}}.offset),
bounds_checker)) { bounds_checker)) {
{%- elif kind|is_struct_kind %}
if (!{{kind|get_name_for_kind}}::Data_::Validate(
mojo::internal::DecodePointerRaw(&object->{{name}}.offset),
bounds_checker)) {
{%- else %} {%- else %}
if (!{{wrapper_type}}::Data_::Validate( if (!{{wrapper_type}}::Data_::Validate(
mojo::internal::DecodePointerRaw(&object->{{name}}.offset), mojo::internal::DecodePointerRaw(&object->{{name}}.offset),
......
...@@ -146,7 +146,7 @@ def GetFieldType(kind, field=None): ...@@ -146,7 +146,7 @@ def GetFieldType(kind, field=None):
return '_descriptor.%s(%s)' % (array_type, ', '.join(arguments)) return '_descriptor.%s(%s)' % (array_type, ', '.join(arguments))
if mojom.IsStructKind(kind): if mojom.IsStructKind(kind):
arguments = [ GetStructClass(kind) ] arguments = [ 'lambda: %s' % GetStructClass(kind) ]
if mojom.IsNullableKind(kind): if mojom.IsNullableKind(kind):
arguments.append('nullable=True') arguments.append('nullable=True')
return '_descriptor.StructType(%s)' % ', '.join(arguments) return '_descriptor.StructType(%s)' % ', '.join(arguments)
......
...@@ -10,6 +10,7 @@ import mojo.system ...@@ -10,6 +10,7 @@ import mojo.system
# Generated files # Generated files
# pylint: disable=F0401 # pylint: disable=F0401
import regression_tests_mojom
import sample_import_mojom import sample_import_mojom
import sample_import2_mojom import sample_import2_mojom
import sample_service_mojom import sample_service_mojom
...@@ -206,3 +207,11 @@ class StructBindingsTest(unittest.TestCase): ...@@ -206,3 +207,11 @@ class StructBindingsTest(unittest.TestCase):
p = sample_import_mojom.Point(0, x=0) p = sample_import_mojom.Point(0, x=0)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
p = sample_import_mojom.Point(c=0) p = sample_import_mojom.Point(c=0)
def testCyclicDefinition(self):
a = regression_tests_mojom.A()
b = regression_tests_mojom.B()
self.assertIsNone(a.b)
self.assertIsNone(b.a)
a.b = b
self.assertIs(a.b, b)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment