Support Option<RustStruct> in arguments/returns

Add all the necessary support in a few locations and we should be good
to go!

Closes #1252
This commit is contained in:
Alex Crichton
2019-02-19 09:08:37 -08:00
parent e498d99b2d
commit f831711f5d
5 changed files with 145 additions and 35 deletions

View File

@ -313,6 +313,18 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
.push(format!("isLikeNone({0}) ? {1} : {0}", name, hole));
return Ok(self);
}
Descriptor::RustStruct(ref s) => {
self.js_arguments.push((name.clone(), format!("{} | undefined", s)));
self.prelude(&format!("let ptr{} = 0;", i));
self.prelude(&format!("if ({0} !== null && {0} !== undefined) {{", name));
self.assert_class(&name, s);
self.assert_not_moved(&name);
self.prelude(&format!("ptr{} = {}.ptr;", i, name));
self.prelude(&format!("{}.ptr = 0;", name));
self.prelude("}");
self.rust_arguments.push(format!("ptr{}", i));
return Ok(self);
}
_ => bail!(
"unsupported optional argument type for calling Rust function from JS: {:?}",
arg
@ -322,44 +334,13 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
if let Some(s) = arg.rust_struct() {
self.js_arguments.push((name.clone(), s.to_string()));
if self.cx.config.debug {
self.cx.expose_assert_class();
self.prelude(&format!(
"\
_assertClass({arg}, {struct_});\n\
",
arg = name,
struct_ = s
));
}
self.assert_class(&name, s);
self.assert_not_moved(&name);
if arg.is_by_ref() {
self.rust_arguments.push(format!("{}.ptr", name));
} else {
self.prelude(&format!(
"\
const ptr{i} = {arg}.ptr;\n\
",
i = i,
arg = name
));
if self.cx.config.debug {
self.prelude(&format!(
"\
if (ptr{i} === 0) {{
throw new Error('Attempt to use a moved value');
}}
",
i = i,
));
}
self.prelude(&format!(
"\
{arg}.ptr = 0;\n\
",
arg = name
));
self.prelude(&format!("const ptr{} = {}.ptr;", i, name));
self.prelude(&format!("{}.ptr = 0;", name));
self.rust_arguments.push(format!("ptr{}", i));
}
return Ok(self);
@ -627,6 +608,17 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
);
return Ok(self);
}
Descriptor::RustStruct(ref name) => {
self.ret_ty = format!("{} | undefined", name);
self.cx.require_class_wrap(name);
self.ret_expr = format!("
const ptr = RET;
return ptr === 0 ? undefined : {}.__wrap(ptr);
",
name,
);
return Ok(self);
}
_ => bail!(
"unsupported optional return type for calling Rust function from JS: {:?}",
ty
@ -764,4 +756,26 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
ts.push(';');
(js, ts, self.js_doc_comments())
}
fn assert_class(&mut self, arg: &str, class: &str) {
if !self.cx.config.debug {
return
}
self.cx.expose_assert_class();
self.prelude(&format!("_assertClass({}, {});", arg, class));
}
fn assert_not_moved(&mut self, arg: &str) {
if !self.cx.config.debug {
return
}
self.prelude(&format!(
"\
if ({0}.ptr === 0) {{
throw new Error('Attempt to use a moved value');
}}
",
arg,
));
}
}

View File

@ -213,6 +213,13 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
));
return Ok(());
}
Descriptor::RustStruct(ref class) => {
self.cx.require_class_wrap(class);
let assign = format!("let c{0} = {0} === 0 ? undefined : {1}.__wrap({0});", abi, class);
self.prelude(&assign);
self.js_arguments.push(format!("c{}", abi));
return Ok(());
}
_ => bail!(
"unsupported optional argument type for calling JS function from Rust: {:?}",
arg
@ -456,6 +463,24 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
);
return Ok(());
}
Descriptor::RustStruct(ref class) => {
// Like below, assert the type
self.ret_expr = format!(
"\
const val = JS;
if (val === undefined || val === null)
return 0;
if (!(val instanceof {0})) {{
throw new Error('expected value of type {0}');
}}
const ret = val.ptr;
val.ptr = 0;
return ret;\
",
class
);
return Ok(());
}
_ => bail!(
"unsupported optional return type for calling JS function from Rust: {:?}",
ty