Commit 6f4137fd authored by Scott Graham's avatar Scott Graham Committed by Commit Bot

Fuchsia: Implement sending unions from JS->C++

Bug: 883496
Change-Id: I2745399b530564c05e95f4375e04cac978454372
Reviewed-on: https://chromium-review.googlesource.com/c/1313417
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#605488}
parent b8316388
......@@ -115,8 +115,8 @@ class Compiler(object):
self._CompileConst(c)
for e in self.fidl.enum_declarations:
self._CompileEnum(e)
if self.fidl.union_declarations:
raise NotImplementedError()
for u in self.fidl.union_declarations:
self._CompileUnion(u)
for s in self.fidl.struct_declarations:
self._CompileStruct(s)
for i in self.fidl.interface_declarations:
......@@ -163,6 +163,85 @@ const %(name)s = {
self.f.write('};\n')
self.f.write('const _kTT_%(name)s = _kTT_%(type)s;\n\n' % data)
def _CompileUnion(self, union):
compound = _ParseCompoundIdentifier(union.name)
name = _CompileCompoundIdentifier(compound)
member_names = []
enc_cases = []
for i, m in enumerate(union.members):
member_name = _ChangeIfReserved(m.name)
member_names.append(member_name)
member_type = self._CompileType(m.type)
enc_cases.append('''\
case %(index)s:
_kTT_%(member_type)s.enc(e, o + 4, v.%(member_name)s);
break;''' % {
'index': i,
'member_type': member_type,
'member_name': member_name,
})
self.f.write('''\
const _kTT_%(name)s = {
enc: function(e, o, v) {
if (v.$tag === $fidl__kInvalidUnionTag) throw "invalid tag";
e.data.setUint32(o, v.$tag, $fidl__kLE);
switch (v.$tag) {
%(enc_cases)s
}
},
dec: function(d, o) {
throw 'not implemented crbug.com/883496'
},
};
const _kTT_%(name)s_Nullable = {
enc: function(e, o, v) {
e.data.setUint32(o, v ? 0xffffffff : 0, $fidl__kLE);
e.data.setUint32(o + 4, v ? 0xffffffff : 0, $fidl__kLE);
e.outOfLine.push([function() {
var start = e.alloc(%(size)s);
_kTT_%(name)s.enc(e, start, v);
}]);
},
dec: function(d, o) {
throw 'not implemented crbug.com/883496'
},
};
/**
* @constructor
*/
function %(name)s() { this.reset(); }
%(name)s.prototype.reset = function(i) {
this.$tag = (i === undefined) ? $fidl__kInvalidUnionTag : i;
''' % {
'name': name,
'size': union.size,
'enc_cases': '\n'.join(enc_cases),
})
for m in member_names:
self.f.write(' this.%s = null;\n' % m)
self.f.write('}\n\n')
for i, m in enumerate(member_names):
self.f.write('''\
%(name)s.prototype.set_%(member_name)s = function(v) {
this.reset(%(index)s);
this.%(member_name)s = v;
};
%(name)s.prototype.is_%(member_name)s = function() {
return this.$tag === %(index)s;
};
''' % {
'name': name,
'member_name': m,
'index': i,
})
def _CompileStruct(self, struct):
compound = _ParseCompoundIdentifier(struct.name)
name = _CompileCompoundIdentifier(compound)
......@@ -183,6 +262,12 @@ function %(name)s(%(param_names)s) {
if member.maybe_default_value:
value = ('(%(member_name)s !== undefined) ? %(member_name)s : ' +
_CompileConstant(member.maybe_default_value))
elif self.fidl.declarations.get(member.type.identifier) == \
fidl.DeclarationsMap.UNION:
union_compound = _ParseCompoundIdentifier(member.type.identifier)
union_name = _CompileCompoundIdentifier(union_compound)
value = ('(%(member_name)s !== undefined) ? %(member_name)s : ' + 'new '
+ union_name + '()')
self.f.write((' this.%(member_name)s = ' + value + ';\n') %
{'member_name': member_name})
self.f.write('}\n\n')
......@@ -224,6 +309,8 @@ function %(name)s(%(param_names)s) {
})
def _CompileType(self, t):
"""Ensures there's a type table for the given type, and returns the stem of
its name."""
if t.kind == fidl.TypeKind.PRIMITIVE:
return t.subtype
elif t.kind == fidl.TypeKind.STRING:
......@@ -231,7 +318,7 @@ function %(name)s(%(param_names)s) {
elif t.kind == fidl.TypeKind.IDENTIFIER:
compound = _ParseCompoundIdentifier(t.identifier)
name = _CompileCompoundIdentifier(compound)
return name
return name + ('_Nullable' if t.nullable else '')
elif t.kind == fidl.TypeKind.HANDLE:
return 'Handle'
elif t.kind == fidl.TypeKind.ARRAY:
......
......@@ -19,6 +19,7 @@ const $fidl__kLE = true;
const $fidl__kUserspaceTxidMask = 0x7fffffff;
const $fidl__kHandlePresent = 0xffffffff;
const $fidl__kInvalidUnionTag = 0xffffffff;
var $fidl__nextTxid = 1;
function $fidl__align(size) {
......
......@@ -220,6 +220,22 @@ class TestolaImpl : public fidljstest::Testola {
callback(std::move(log));
}
void ReceiveUnions(fidljstest::StructOfMultipleUnions somu) override {
EXPECT_TRUE(somu.initial.is_swb());
EXPECT_TRUE(somu.initial.swb().some_bool);
EXPECT_TRUE(somu.optional.get());
EXPECT_TRUE(somu.optional->is_lswa());
for (int i = 0; i < 32; ++i) {
EXPECT_EQ(somu.optional->lswa().components[i], i * 99);
}
EXPECT_TRUE(somu.trailing.is_swu());
EXPECT_EQ(somu.trailing.swu().length, 123456u);
did_receive_union_ = true;
}
bool was_do_something_called() const { return was_do_something_called_; }
int32_t received_int() const { return received_int_; }
const std::string& received_msg() const { return received_msg_; }
......@@ -232,6 +248,8 @@ class TestolaImpl : public fidljstest::Testola {
fidljstest::BasicStruct GetReceivedStruct() const { return basic_struct_; }
bool did_receive_union() const { return did_receive_union_; }
void CallResponseCallbacks() {
for (auto& cb : response_callbacks_) {
std::move(cb).Run();
......@@ -249,6 +267,7 @@ class TestolaImpl : public fidljstest::Testola {
fidljstest::BasicStruct basic_struct_;
std::vector<base::OnceClosure> response_callbacks_;
zx_handle_t unowned_log_handle_;
bool did_receive_union_ = false;
DISALLOW_COPY_AND_ASSIGN(TestolaImpl);
};
......@@ -594,6 +613,41 @@ TEST_F(FidlGenJsTest, HandlePassing) {
EXPECT_NE(GetKoidForHandle(*zx::job::default_job()), ZX_KOID_INVALID);
}
TEST_F(FidlGenJsTest, UnionSend) {
v8::Isolate* isolate = instance_->isolate();
BindingsSetupHelper helper(isolate);
TestolaImpl testola_impl;
fidl::Binding<fidljstest::Testola> binding(&testola_impl);
binding.Bind(std::move(helper.server()));
std::string source = R"(
var proxy = new TestolaProxy();
proxy.$bind(testHandle);
var somu = new StructOfMultipleUnions();
var swb = new StructWithBool(/*some_bool*/ true);
somu.initial.set_swb(swb);
var lswa = new LargerStructWithArray([]);
for (var i = 0; i < 32; ++i) {
lswa.components[i] = i * 99;
}
somu.optional.set_lswa(lswa);
somu.trailing.set_swu(new StructWithUint(123456));
proxy.ReceiveUnions(somu);
)";
helper.runner().Run(source, "test.js");
base::RunLoop().RunUntilIdle();
// Expectations on the contents of the union are checked in the body of
// TestolaImpl::ReceiveAUnion().
EXPECT_TRUE(testola_impl.did_receive_union());
}
int main(int argc, char** argv) {
base::TestSuite test_suite(argc, argv);
......
......@@ -33,6 +33,30 @@ struct StuffAndThings {
array<int32>:ARRRR_SIZE arrrr;
};
struct StructWithBool {
bool some_bool = false;
};
struct StructWithUint {
uint32 length;
};
struct LargerStructWithArray {
array<int32>:32 components;
};
union UnionOfStructs {
StructWithBool swb;
StructWithUint swu;
LargerStructWithArray lswa;
};
struct StructOfMultipleUnions {
UnionOfStructs initial;
UnionOfStructs? optional;
UnionOfStructs trailing;
};
interface Testola {
1: DoSomething();
......@@ -49,4 +73,6 @@ interface Testola {
7: NestedStructsWithResponse(BasicStruct basic) -> (StuffAndThings resp);
8: PassHandles(handle<job> job) -> (handle<debuglog> debuglog);
9: ReceiveUnions(StructOfMultipleUnions somu);
};
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