diff --git a/examples/memory_management/main.cpp b/examples/memory_management/main.cpp index d3a4201..fa8e4ec 100644 --- a/examples/memory_management/main.cpp +++ b/examples/memory_management/main.cpp @@ -1,19 +1,14 @@ +#include #include #include #include "./generated.h" -// Rust values are available in the `::rust` namespace from their absolute path -// in Rust template using Vec = rust::std::vec::Vec; template using Option = rust::std::option::Option; template using BoxDyn = rust::Box>; template using RmDyn = rust::RefMut>; -using rust::crate::consume_and_panic; -using rust::crate::consume_n_times; -using rust::crate::PrintOnDrop; -using rust::crate::PrintOnDropConsumer; -using rust::crate::PrintOnDropPair; +using namespace rust::crate; class CppPrintOnDropHolder : public PrintOnDropConsumer { rust::Unit consume(PrintOnDrop p) override { @@ -139,8 +134,7 @@ int main() { const char *elems[3] = {"elem1", "elem2", "elem3"}; int i = 0; auto iter = rust::std::iter::from_fn( - ::rust::Box<::rust::Dyn<::rust::Fn<::rust::std::option::Option< - ::rust::crate::PrintOnDrop>>>>::make_box([&] { + rust::Box>>>::make_box([&] { if (i == 3) { return Option::None(); } @@ -149,12 +143,18 @@ int main() { })); std::cout << "Checkpoint 41" << std::endl; iter.for_each( - ::rust::Box< - ::rust::Dyn<::rust::Fn<::rust::crate::PrintOnDrop, rust::Unit>>>:: - make_box([](PrintOnDrop p) -> rust::Unit { + rust::Box>>::make_box( + [](PrintOnDrop p) -> rust::Unit { std::cout << "Checkpoint 42" << std::endl; return {}; })); } std::cout << "Checkpoint 43" << std::endl; + { + auto tuple = rust::Tuple( + PrintOnDrop(rust::Str::from_char_star("field_0")), 5, + PrintOnDrop(rust::Str::from_char_star("field_2"))); + std::cout << "Checkpoint 44" << std::endl; + } + std::cout << "Checkpoint 45" << std::endl; } diff --git a/examples/memory_management/main.zng b/examples/memory_management/main.zng index 722f8dc..b8f0efe 100644 --- a/examples/memory_management/main.zng +++ b/examples/memory_management/main.zng @@ -5,6 +5,10 @@ type () { wellknown_traits(Copy); } +type (crate::PrintOnDrop, i32, crate::PrintOnDrop) { + #layout(size = 40, align = 8); +} + type bool { #layout(size = 1, align = 1); wellknown_traits(Copy); diff --git a/examples/memory_management/out.txt b/examples/memory_management/out.txt index 7a94788..2dff9a5 100644 --- a/examples/memory_management/out.txt +++ b/examples/memory_management/out.txt @@ -40,7 +40,8 @@ Checkpoint 20 Checkpoint 21 PrintOnDrop(A) has been dropped Checkpoint 22 -thread '' panicked at 'consume_and_panic executed with value B', examples/memory_management/src/lib.rs:29:9 +thread '' panicked at examples/memory_management/src/lib.rs:29:9: +consume_and_panic executed with value B note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace PrintOnDrop(B) has been dropped PrintOnDrop(A) has been dropped @@ -58,15 +59,15 @@ Checkpoint 30 PrintOnDrop(elem1) has been dropped PrintOnDrop(elem2) has been dropped Checkpoint 31 -[main.cpp:117] PrintOnDrop(rust::Str::from_char_star("dbg_A")) = PrintOnDrop( +[main.cpp:112] PrintOnDrop(rust::Str::from_char_star("dbg_A")) = PrintOnDrop( "dbg_A", ) Checkpoint 32 -[main.cpp:119] std::move(p1) = PrintOnDrop( +[main.cpp:114] std::move(p1) = PrintOnDrop( "dbg_A", ) Checkpoint 33 -[main.cpp:121] p2 = PrintOnDrop( +[main.cpp:116] p2 = PrintOnDrop( "dbg_A", ) Checkpoint 34 @@ -80,9 +81,15 @@ Checkpoint 39 PrintOnDrop(option_A) has been dropped Checkpoint 40 Checkpoint 41 -PrintOnDrop(iter_elem) has been dropped -PrintOnDrop(iter_elem) has been dropped -PrintOnDrop(iter_elem) has been dropped Checkpoint 42 +PrintOnDrop(elem1) has been dropped +Checkpoint 42 +PrintOnDrop(elem2) has been dropped +Checkpoint 42 +PrintOnDrop(elem3) has been dropped Checkpoint 43 +Checkpoint 44 +PrintOnDrop(field_0) has been dropped +PrintOnDrop(field_2) has been dropped +Checkpoint 45 PrintOnDrop(C) has been dropped diff --git a/zngur-generator/src/lib.rs b/zngur-generator/src/lib.rs index e61d24a..f63a4f4 100644 --- a/zngur-generator/src/lib.rs +++ b/zngur-generator/src/lib.rs @@ -97,6 +97,16 @@ impl ZngurGenerator { } } } + if let RustType::Tuple(fields) = &ty_def.ty { + if !fields.is_empty() { + let rust_link_name = rust_file.add_tuple_constructor(&fields); + constructors.push(CppFnSig { + rust_link_name, + inputs: fields.iter().map(|x| x.into_cpp()).collect(), + output: ty_def.ty.into_cpp(), + }); + } + } for wellknown_trait in ty_def.wellknown_traits { let data = rust_file.add_wellknown_trait(&ty_def.ty, wellknown_trait); wellknown_traits.push(data); diff --git a/zngur-generator/src/rust.rs b/zngur-generator/src/rust.rs index e397d41..bd9dacc 100644 --- a/zngur-generator/src/rust.rs +++ b/zngur-generator/src/rust.rs @@ -109,7 +109,10 @@ impl IntoCpp for RustType { if v.is_empty() { return CppType::from("rust::Unit"); } - todo!() + CppType { + path: CppPath::from("rust::Tuple"), + generic_args: v.into_iter().map(|x| x.into_cpp()).collect(), + } } RustType::Dyn(tr, marker_bounds) => { let tr_as_cpp_type = tr.into_cpp(); @@ -473,6 +476,30 @@ pub extern "C" fn {mangled_name}( mangled_name } + pub fn add_tuple_constructor(&mut self, fields: &[RustType]) -> String { + let constructor = mangle_name(&fields.iter().join("&")); + w!( + self, + r#" +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn {constructor}("# + ); + for name in 0..fields.len() { + w!(self, "f_{name}: *mut u8, "); + } + w!( + self, + r#"o: *mut u8) {{ unsafe {{ + ::std::ptr::write(o as *mut _, ("# + ); + for (name, ty) in fields.iter().enumerate() { + w!(self, "::std::ptr::read(f_{name} as *mut {ty}), "); + } + wln!(self, ")) }} }}"); + constructor + } + pub fn add_constructor( &mut self, rust_name: &str, diff --git a/zngur-parser/src/lib.rs b/zngur-parser/src/lib.rs index e347a2b..a0e2a2c 100644 --- a/zngur-parser/src/lib.rs +++ b/zngur-parser/src/lib.rs @@ -725,6 +725,13 @@ fn rust_type<'a>( let unit = just(Token::ParenOpen) .then(just(Token::ParenClose)) .map(|_| ParsedRustType::Tuple(vec![])); + let tuple = parser + .clone() + .separated_by(just(Token::Comma)) + .allow_trailing() + .collect::>() + .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)) + .map(|xs| ParsedRustType::Tuple(xs)); let slice = parser .clone() .map(|x| ParsedRustType::Slice(Box::new(x))) @@ -748,6 +755,7 @@ fn rust_type<'a>( scalar .or(boxed) .or(unit) + .or(tuple) .or(slice) .or(adt) .or(reference) diff --git a/zngur-parser/src/tests.rs b/zngur-parser/src/tests.rs index 624cf0a..72fef89 100644 --- a/zngur-parser/src/tests.rs +++ b/zngur-parser/src/tests.rs @@ -35,6 +35,17 @@ type () { ); } +#[test] +fn parse_tuple() { + check_success( + r#" +type (i8, u8) { + #layout(size = 0, align = 1); +} + "#, + ); +} + #[test] fn typo_in_wellknown_trait() { check_fail(