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> {
}
};
// 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>
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) {
size_t size =
sizeof(Array_Data<typename S::Data_*>) +
input.size() * sizeof(internal::StructPointer<typename S::Data_>);
size_t size = sizeof(Array_Data<S_Data*>) +
input.size() * sizeof(internal::StructPointer<S_Data>);
for (size_t i = 0; i < input.size(); ++i)
size += GetSerializedSize_(input[i]);
return size;
......@@ -145,9 +153,9 @@ struct ArraySerializer<S, typename S::Data_*, true> {
template <bool element_is_nullable, typename ElementValidateParams>
static void SerializeElements(Array<S> input,
Buffer* buf,
Array_Data<typename S::Data_*>* output) {
Array_Data<S_Data*>* output) {
for (size_t i = 0; i < input.size(); ++i) {
typename S::Data_* element;
S_Data* element;
SerializeCaller<S, ElementValidateParams>::Run(
input[i].Pass(), buf, &element);
output->at(i) = element;
......@@ -158,7 +166,7 @@ struct ArraySerializer<S, typename S::Data_*, true> {
"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> result(input->size());
for (size_t i = 0; i < input->size(); ++i) {
......@@ -172,7 +180,9 @@ struct ArraySerializer<S, typename S::Data_*, true> {
private:
template <typename T, typename Params>
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),
"Struct type should not have array validate params");
......
......@@ -6,6 +6,7 @@
#define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDINGS_INTERNAL_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"
namespace mojo {
......@@ -81,6 +82,14 @@ struct WrapperTraits<ScopedHandleBase<H>, true> {
typedef H DataType;
};
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> {
typedef typename S::Data_* DataType;
};
......
......@@ -24,6 +24,11 @@ struct IsConst : FalseType {};
template <class T>
struct IsConst<const T> : TrueType {};
template <class T>
struct IsPointer : FalseType {};
template <class T>
struct IsPointer<T*> : TrueType {};
template <bool B, typename T = void>
struct EnableIf {};
......@@ -92,6 +97,13 @@ struct IsBaseOf {
!IsSame<Base const, void const>::value;
};
template <class T>
struct RemovePointer {};
template <class T>
struct RemovePointer<T*> {
typedef T type;
};
} // namespace internal
} // namespace mojo
......
......@@ -7,6 +7,7 @@
#include <new>
#include "mojo/public/cpp/bindings/type_converter.h"
#include "mojo/public/cpp/environment/logging.h"
#include "mojo/public/cpp/system/macros.h"
......@@ -29,7 +30,6 @@ class StructPtr {
MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(StructPtr, RValue);
public:
typedef typename Struct::Data_ Data_;
StructPtr() : ptr_(nullptr) {}
~StructPtr() { delete ptr_; }
......@@ -98,7 +98,6 @@ class InlinedStructPtr {
MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InlinedStructPtr, RValue);
public:
typedef typename Struct::Data_ Data_;
InlinedStructPtr() : is_null_(true) {}
~InlinedStructPtr() {}
......
......@@ -44,7 +44,8 @@ class SerializationWarningTest : public testing::Test {
protected:
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);
mojo::internal::FixedBuffer buf(GetSerializedSize_(obj));
......
......@@ -34,4 +34,23 @@ enum EnumWithK {
K = 0
};
struct Edge {
Vertex? v;
};
struct Vertex {
EmptyStruct? e;
};
struct EmptyStruct {
};
struct A {
B? b;
};
struct B {
A? a;
};
} // module imported
......@@ -372,11 +372,18 @@ class NativeArrayType(BaseArrayType):
class StructType(PointerType):
"""Type object for structs."""
def __init__(self, struct_type, nullable=False):
def __init__(self, struct_type_getter, nullable=False):
PointerType.__init__(self)
self.struct_type = struct_type
self._struct_type_getter = struct_type_getter
self._struct_type = None
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):
if value is None or isinstance(value, self.struct_type):
return value
......
......@@ -32,6 +32,11 @@ class {{struct.name}};
namespace internal {
{#--- Internal forward declarations #}
{% for struct in structs %}
class {{struct.name}}_Data;
{%- endfor %}
#pragma pack(push, 1)
{#--- Class declarations #}
......
......@@ -38,6 +38,10 @@
{{kind.value_kind|get_map_validate_params|indent(10)}}>(
mojo::internal::DecodePointerRaw(&object->{{name}}.offset),
bounds_checker)) {
{%- elif kind|is_struct_kind %}
if (!{{kind|get_name_for_kind}}::Data_::Validate(
mojo::internal::DecodePointerRaw(&object->{{name}}.offset),
bounds_checker)) {
{%- else %}
if (!{{wrapper_type}}::Data_::Validate(
mojo::internal::DecodePointerRaw(&object->{{name}}.offset),
......
......@@ -146,7 +146,7 @@ def GetFieldType(kind, field=None):
return '_descriptor.%s(%s)' % (array_type, ', '.join(arguments))
if mojom.IsStructKind(kind):
arguments = [ GetStructClass(kind) ]
arguments = [ 'lambda: %s' % GetStructClass(kind) ]
if mojom.IsNullableKind(kind):
arguments.append('nullable=True')
return '_descriptor.StructType(%s)' % ', '.join(arguments)
......
......@@ -10,6 +10,7 @@ import mojo.system
# Generated files
# pylint: disable=F0401
import regression_tests_mojom
import sample_import_mojom
import sample_import2_mojom
import sample_service_mojom
......@@ -206,3 +207,11 @@ class StructBindingsTest(unittest.TestCase):
p = sample_import_mojom.Point(0, x=0)
with self.assertRaises(TypeError):
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