Skip to content

Commit 6296214

Browse files
committed
c++/feature: make possible to return Option<&ForeignClass>
may be it is possible to simplify code after resolving rust-lang/rust#48869
1 parent e1e20fa commit 6296214

File tree

5 files changed

+122
-5
lines changed

5 files changed

+122
-5
lines changed

c++_tests/c++/main.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,20 @@ TEST(TestOptional, smokeTest)
353353
ASSERT_FALSE(!!val2);
354354
}
355355

356-
EXPECT_NEAR(10., x.f4({5.}), std::numeric_limits<double>::epsilon());
356+
EXPECT_NEAR(10., x.f4({ 5. }), std::numeric_limits<double>::epsilon());
357357
EXPECT_NEAR(-1., x.f4({}), std::numeric_limits<double>::epsilon());
358+
359+
{
360+
auto val = x.f5(true);
361+
ASSERT_TRUE(!!val);
362+
FooRef foo = std::move(*val);
363+
EXPECT_EQ(5, foo.f(0, 0));
364+
EXPECT_EQ(std::string("aaa"), foo.getName().to_std_string());
365+
}
366+
{
367+
auto foo = x.f5(false);
368+
EXPECT_FALSE(!!foo);
369+
}
358370
}
359371

360372
TEST(TestResult, smokeTest)

c++_tests/src/lib.rs.in

+18-2
Original file line numberDiff line numberDiff line change
@@ -365,9 +365,17 @@ foreigner_class!(class TestPassPathAsParam {
365365
method TestPassPathAsParam::path(&self) -> &str;
366366
});
367367

368-
#[derive(Default)]
369-
pub struct TestOptional {}
368+
pub struct TestOptional {
369+
foo: Foo,
370+
}
370371

372+
impl Default for TestOptional {
373+
fn default() -> TestOptional {
374+
TestOptional {
375+
foo: Foo::new(5, "aaa"),
376+
}
377+
}
378+
}
371379
impl TestOptional {
372380
fn f1(&self, ret_notnull: bool) -> Option<Foo> {
373381
if ret_notnull {
@@ -395,6 +403,13 @@ impl TestOptional {
395403
fn f4(&self, a: Option<f64>) -> f64 {
396404
a.map(|v| v * 2.).unwrap_or(-1.)
397405
}
406+
fn f5(&self, x: bool) -> Option<&Foo> {
407+
if x {
408+
Some(&self.foo)
409+
} else {
410+
None
411+
}
412+
}
398413
}
399414

400415
foreigner_class!(class TestOptional {
@@ -404,6 +419,7 @@ foreigner_class!(class TestOptional {
404419
method TestOptional::f2(&self, ret_notnull: bool) -> Option<f64>;
405420
method TestOptional::f3(&self, ret_notnull: bool) -> Option<u32>;
406421
method TestOptional::f4(&self, _: Option<f64>) -> f64;
422+
method TestOptional::f5(&self, x: bool) -> Option<&Foo>;
407423
});
408424

409425
#[derive(Default)]

macroslib/src/cpp/map_type.rs

+82-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use petgraph::Direction;
88
use my_ast::{code_to_item, if_option_return_some_type, if_result_return_ok_err_types,
99
if_vec_return_elem_type, normalized_ty_string, parse_ty, RustType};
1010
use errors::fatal_error;
11-
use types_conv_map::{ForeignTypeInfo, FROM_VAR_TEMPLATE};
11+
use types_conv_map::{make_unique_rust_typename, ForeignTypeInfo, FROM_VAR_TEMPLATE,
12+
TO_VAR_TEMPLATE};
1213
use {CppConfig, CppOptional, CppVariant, ForeignEnumInfo, ForeignerClassInfo, TypesConvMap};
1314
use cpp::{CppConverter, CppForeignTypeInfo};
1415
use cpp::cpp_code::c_class_type;
@@ -571,6 +572,86 @@ fn handle_option_type_in_result<'a>(
571572
}),
572573
}));
573574
}
575+
576+
//handle Option<&ForeignClass> case
577+
if let ast::TyKind::Rptr(
578+
_,
579+
ast::MutTy {
580+
ty: ref under_ref_ty,
581+
mutbl: ast::Mutability::Immutable,
582+
},
583+
) = opt_ty.node
584+
{
585+
if let Some(fclass) = conv_map
586+
.find_foreigner_class_with_such_self_type(under_ref_ty, false)
587+
.map(|v| v.clone())
588+
{
589+
let foreign_info =
590+
foreign_class_foreign_name(sess, conv_map, &fclass, under_ref_ty.span, false)?;
591+
let this_type_for_method = fclass.this_type_for_method.as_ref().ok_or_else(|| {
592+
fatal_error(
593+
sess,
594+
fclass.span,
595+
&format!(
596+
"Class {} (namespace {}) return as reference, but there is no constructor",
597+
fclass.name, cpp_cfg.namespace_name,
598+
),
599+
)
600+
})?;
601+
let this_type: RustType = this_type_for_method.clone().into();
602+
let void_ptr_typename = Symbol::intern("*mut ::std::os::raw::c_void");
603+
let my_void_ptr_ti = RustType::new(
604+
parse_ty(sess, DUMMY_SP, void_ptr_typename)?,
605+
make_unique_rust_typename(void_ptr_typename, this_type.normalized_name),
606+
);
607+
let arg_rust_ty: RustType = arg_ty.clone().into();
608+
conv_map.add_type(arg_rust_ty.clone());
609+
conv_map.add_conversation_rule(
610+
arg_rust_ty,
611+
my_void_ptr_ti,
612+
Symbol::intern(&format!(
613+
r#"
614+
let {to_var}: *mut ::std::os::raw::c_void = match {from_var} {{
615+
Some(x) => x as *const {self_type} as *mut ::std::os::raw::c_void,
616+
None => ::std::ptr::null_mut(),
617+
}};
618+
"#,
619+
to_var = TO_VAR_TEMPLATE,
620+
from_var = FROM_VAR_TEMPLATE,
621+
self_type = this_type.normalized_name,
622+
)).into(),
623+
);
624+
625+
let (typename, output_converter) = match cpp_cfg.cpp_optional {
626+
CppOptional::Std17 => (
627+
Symbol::intern(&format!("std::optional<{}Ref>", fclass.name)),
628+
format!(
629+
"{var} != nullptr ? {Type}Ref({var}) : std::optional<{Type}Ref>()",
630+
Type = fclass.name,
631+
var = FROM_VAR_TEMPLATE,
632+
),
633+
),
634+
CppOptional::Boost => (
635+
Symbol::intern(&format!("boost::optional<{}Ref>", fclass.name)),
636+
format!(
637+
"{var} != nullptr ? {Type}Ref({var}) : boost::optional<{Type}Ref>()",
638+
Type = fclass.name,
639+
var = FROM_VAR_TEMPLATE,
640+
),
641+
),
642+
};
643+
return Ok(Some(CppForeignTypeInfo {
644+
base: foreign_info,
645+
c_converter: String::new(),
646+
cpp_converter: Some(CppConverter {
647+
typename,
648+
output_converter,
649+
input_converter: "#error".to_string(),
650+
}),
651+
}));
652+
}
653+
}
654+
574655
let mut cpp_info_opt = map_ordinal_result_type(sess, conv_map, arg_ty)?;
575656
let cpp_info_ty = map_ordinal_result_type(sess, conv_map, opt_ty)?;
576657
let f_opt_ty = cpp_info_ty.base.name;

macroslib/src/types_conv_map/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ impl TypesConvMap {
780780
debug!("TypesConvMap::add_conversation_rule {} -> {}", from, to);
781781
let from = get_graph_node(&mut self.conv_graph, &mut self.rust_names_map, from);
782782
let to = get_graph_node(&mut self.conv_graph, &mut self.rust_names_map, to);
783-
self.conv_graph.add_edge(from, to, rule);
783+
self.conv_graph.update_edge(from, to, rule);
784784
}
785785

786786
pub(crate) fn register_exported_enum(&mut self, enum_info: &ForeignEnumInfo) {

macroslib/tests/test_complex_cases.rs

+8
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ foreigner_class!(class Foo {
651651
method Foo::f2(&self) -> Option<f64>;
652652
method Foo::f3(&self) -> Option<u32>;
653653
method Foo::f4(&self) -> Option<usize>;
654+
method Foo::f5(&self) -> Option<&Boo>;
654655
});
655656
"#,
656657
&[ForeignLang::Cpp],
@@ -659,7 +660,9 @@ foreigner_class!(class Foo {
659660
.iter()
660661
.find(|x| x.lang == ForeignLang::Cpp)
661662
.unwrap();
663+
println!("Rust: {}", cpp_code_pair.rust_code);
662664
println!("c/c++: {}", cpp_code_pair.foreign_code);
665+
assert!(false);
663666
assert!(
664667
cpp_code_pair
665668
.foreign_code
@@ -681,6 +684,11 @@ foreigner_class!(class Foo {
681684
.foreign_code
682685
.contains("std::optional<uintptr_t> f4()")
683686
);
687+
assert!(
688+
cpp_code_pair
689+
.foreign_code
690+
.contains("std::optional<BooRef> f5()")
691+
);
684692
}
685693

686694
#[test]

0 commit comments

Comments
 (0)