Skip to content

Commit

Permalink
c++/feature: make possible to return Option<&ForeignClass>
Browse files Browse the repository at this point in the history
may be it is possible to simplify code after
resolving rust-lang/rust#48869
  • Loading branch information
Dushistov committed Apr 26, 2018
1 parent e1e20fa commit 6296214
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 5 deletions.
14 changes: 13 additions & 1 deletion c++_tests/c++/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,20 @@ TEST(TestOptional, smokeTest)
ASSERT_FALSE(!!val2);
}

EXPECT_NEAR(10., x.f4({5.}), std::numeric_limits<double>::epsilon());
EXPECT_NEAR(10., x.f4({ 5. }), std::numeric_limits<double>::epsilon());
EXPECT_NEAR(-1., x.f4({}), std::numeric_limits<double>::epsilon());

{
auto val = x.f5(true);
ASSERT_TRUE(!!val);
FooRef foo = std::move(*val);
EXPECT_EQ(5, foo.f(0, 0));
EXPECT_EQ(std::string("aaa"), foo.getName().to_std_string());
}
{
auto foo = x.f5(false);
EXPECT_FALSE(!!foo);
}
}

TEST(TestResult, smokeTest)
Expand Down
20 changes: 18 additions & 2 deletions c++_tests/src/lib.rs.in
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,17 @@ foreigner_class!(class TestPassPathAsParam {
method TestPassPathAsParam::path(&self) -> &str;
});

#[derive(Default)]
pub struct TestOptional {}
pub struct TestOptional {
foo: Foo,
}

impl Default for TestOptional {
fn default() -> TestOptional {
TestOptional {
foo: Foo::new(5, "aaa"),
}
}
}
impl TestOptional {
fn f1(&self, ret_notnull: bool) -> Option<Foo> {
if ret_notnull {
Expand Down Expand Up @@ -395,6 +403,13 @@ impl TestOptional {
fn f4(&self, a: Option<f64>) -> f64 {
a.map(|v| v * 2.).unwrap_or(-1.)
}
fn f5(&self, x: bool) -> Option<&Foo> {
if x {
Some(&self.foo)
} else {
None
}
}
}

foreigner_class!(class TestOptional {
Expand All @@ -404,6 +419,7 @@ foreigner_class!(class TestOptional {
method TestOptional::f2(&self, ret_notnull: bool) -> Option<f64>;
method TestOptional::f3(&self, ret_notnull: bool) -> Option<u32>;
method TestOptional::f4(&self, _: Option<f64>) -> f64;
method TestOptional::f5(&self, x: bool) -> Option<&Foo>;
});

#[derive(Default)]
Expand Down
83 changes: 82 additions & 1 deletion macroslib/src/cpp/map_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use petgraph::Direction;
use my_ast::{code_to_item, if_option_return_some_type, if_result_return_ok_err_types,
if_vec_return_elem_type, normalized_ty_string, parse_ty, RustType};
use errors::fatal_error;
use types_conv_map::{ForeignTypeInfo, FROM_VAR_TEMPLATE};
use types_conv_map::{make_unique_rust_typename, ForeignTypeInfo, FROM_VAR_TEMPLATE,
TO_VAR_TEMPLATE};
use {CppConfig, CppOptional, CppVariant, ForeignEnumInfo, ForeignerClassInfo, TypesConvMap};
use cpp::{CppConverter, CppForeignTypeInfo};
use cpp::cpp_code::c_class_type;
Expand Down Expand Up @@ -571,6 +572,86 @@ fn handle_option_type_in_result<'a>(
}),
}));
}

//handle Option<&ForeignClass> case
if let ast::TyKind::Rptr(
_,
ast::MutTy {
ty: ref under_ref_ty,
mutbl: ast::Mutability::Immutable,
},
) = opt_ty.node
{
if let Some(fclass) = conv_map
.find_foreigner_class_with_such_self_type(under_ref_ty, false)
.map(|v| v.clone())
{
let foreign_info =
foreign_class_foreign_name(sess, conv_map, &fclass, under_ref_ty.span, false)?;
let this_type_for_method = fclass.this_type_for_method.as_ref().ok_or_else(|| {
fatal_error(
sess,
fclass.span,
&format!(
"Class {} (namespace {}) return as reference, but there is no constructor",
fclass.name, cpp_cfg.namespace_name,
),
)
})?;
let this_type: RustType = this_type_for_method.clone().into();
let void_ptr_typename = Symbol::intern("*mut ::std::os::raw::c_void");
let my_void_ptr_ti = RustType::new(
parse_ty(sess, DUMMY_SP, void_ptr_typename)?,
make_unique_rust_typename(void_ptr_typename, this_type.normalized_name),
);
let arg_rust_ty: RustType = arg_ty.clone().into();
conv_map.add_type(arg_rust_ty.clone());
conv_map.add_conversation_rule(
arg_rust_ty,
my_void_ptr_ti,
Symbol::intern(&format!(
r#"
let {to_var}: *mut ::std::os::raw::c_void = match {from_var} {{
Some(x) => x as *const {self_type} as *mut ::std::os::raw::c_void,
None => ::std::ptr::null_mut(),
}};
"#,
to_var = TO_VAR_TEMPLATE,
from_var = FROM_VAR_TEMPLATE,
self_type = this_type.normalized_name,
)).into(),
);

let (typename, output_converter) = match cpp_cfg.cpp_optional {
CppOptional::Std17 => (
Symbol::intern(&format!("std::optional<{}Ref>", fclass.name)),
format!(
"{var} != nullptr ? {Type}Ref({var}) : std::optional<{Type}Ref>()",
Type = fclass.name,
var = FROM_VAR_TEMPLATE,
),
),
CppOptional::Boost => (
Symbol::intern(&format!("boost::optional<{}Ref>", fclass.name)),
format!(
"{var} != nullptr ? {Type}Ref({var}) : boost::optional<{Type}Ref>()",
Type = fclass.name,
var = FROM_VAR_TEMPLATE,
),
),
};
return Ok(Some(CppForeignTypeInfo {
base: foreign_info,
c_converter: String::new(),
cpp_converter: Some(CppConverter {
typename,
output_converter,
input_converter: "#error".to_string(),
}),
}));
}
}

let mut cpp_info_opt = map_ordinal_result_type(sess, conv_map, arg_ty)?;
let cpp_info_ty = map_ordinal_result_type(sess, conv_map, opt_ty)?;
let f_opt_ty = cpp_info_ty.base.name;
Expand Down
2 changes: 1 addition & 1 deletion macroslib/src/types_conv_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ impl TypesConvMap {
debug!("TypesConvMap::add_conversation_rule {} -> {}", from, to);
let from = get_graph_node(&mut self.conv_graph, &mut self.rust_names_map, from);
let to = get_graph_node(&mut self.conv_graph, &mut self.rust_names_map, to);
self.conv_graph.add_edge(from, to, rule);
self.conv_graph.update_edge(from, to, rule);
}

pub(crate) fn register_exported_enum(&mut self, enum_info: &ForeignEnumInfo) {
Expand Down
8 changes: 8 additions & 0 deletions macroslib/tests/test_complex_cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ foreigner_class!(class Foo {
method Foo::f2(&self) -> Option<f64>;
method Foo::f3(&self) -> Option<u32>;
method Foo::f4(&self) -> Option<usize>;
method Foo::f5(&self) -> Option<&Boo>;
});
"#,
&[ForeignLang::Cpp],
Expand All @@ -659,7 +660,9 @@ foreigner_class!(class Foo {
.iter()
.find(|x| x.lang == ForeignLang::Cpp)
.unwrap();
println!("Rust: {}", cpp_code_pair.rust_code);
println!("c/c++: {}", cpp_code_pair.foreign_code);
assert!(false);
assert!(
cpp_code_pair
.foreign_code
Expand All @@ -681,6 +684,11 @@ foreigner_class!(class Foo {
.foreign_code
.contains("std::optional<uintptr_t> f4()")
);
assert!(
cpp_code_pair
.foreign_code
.contains("std::optional<BooRef> f5()")
);
}

#[test]
Expand Down

0 comments on commit 6296214

Please sign in to comment.