Skip to content

Commit b4f0f78

Browse files
committed
[bindings] Add support for Option<T> where T is a mapped trait
When mapping an `Option<T>` where T is a mapped trait, we need to move out of the `*mut T`, however the current generation results in a `*const T` and a conversion that just takes a reference to the pointed-to object. This is because the only place this code was previously used was for slices, which *do* need a reference. Additionally, we need to know how to convert `Option` containers which do not contain an opaque type. Sadly, the easiest way to get the desired result is to add another special case in container mapping, keeping the current behavior for slices, but moving out of the pointed-to object for other types.
1 parent d633354 commit b4f0f78

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

c-bindings-gen/src/types.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -759,12 +759,16 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
759759

760760
if let Some(t) = single_contained {
761761
let mut v = Vec::new();
762-
let needs_deref = self.write_empty_rust_val_check_suffix(generics, &mut v, t);
762+
let (needs_deref, ret_ref) = self.write_empty_rust_val_check_suffix(generics, &mut v, t);
763763
let s = String::from_utf8(v).unwrap();
764-
if needs_deref {
764+
if needs_deref && ret_ref {
765765
return Some(("if ", vec![
766766
(format!("{} {{ None }} else {{ Some(", s), format!("unsafe {{ &mut *{} }}", var_access))
767767
], ") }"));
768+
} else if needs_deref {
769+
return Some(("if ", vec![
770+
(format!("{} {{ None }} else {{ Some(", s), format!("unsafe {{ *Box::from_raw({}) }}", var_access))
771+
], ") }"));
768772
} else {
769773
return Some(("if ", vec![
770774
(format!("{} {{ None }} else {{ Some(", s), format!("{}", var_access))
@@ -1058,36 +1062,36 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
10581062
/// Prints a suffix to determine if a variable is empty (ie was set by write_empty_rust_val),
10591063
/// returning whether we need to dereference the inner value before using it (ie it is a
10601064
/// pointer).
1061-
pub fn write_empty_rust_val_check_suffix<W: std::io::Write>(&self, generics: Option<&GenericTypes>, w: &mut W, t: &syn::Type) -> bool {
1065+
pub fn write_empty_rust_val_check_suffix<W: std::io::Write>(&self, generics: Option<&GenericTypes>, w: &mut W, t: &syn::Type) -> (bool, bool) {
10621066
match t {
10631067
syn::Type::Path(p) => {
10641068
let resolved = self.resolve_path(&p.path, generics);
10651069
if self.crate_types.opaques.get(&resolved).is_some() {
10661070
write!(w, ".inner.is_null()").unwrap();
1067-
false
1071+
(false, false)
10681072
} else {
10691073
if let Some(suffix) = self.empty_val_check_suffix_from_path(&resolved) {
10701074
write!(w, "{}", suffix).unwrap();
1071-
false // We may eventually need to allow empty_val_check_suffix_from_path to specify if we need a deref or not
1075+
(false, false) // We may eventually need to allow empty_val_check_suffix_from_path to specify if we need a deref or not
10721076
} else {
10731077
write!(w, " == std::ptr::null_mut()").unwrap();
1074-
false
1078+
(true, false)
10751079
}
10761080
}
10771081
},
10781082
syn::Type::Array(a) => {
10791083
if let syn::Expr::Lit(l) = &a.len {
10801084
if let syn::Lit::Int(i) = &l.lit {
10811085
write!(w, " == [0; {}]", i.base10_digits()).unwrap();
1082-
false
1086+
(false, false)
10831087
} else { unimplemented!(); }
10841088
} else { unimplemented!(); }
10851089
},
10861090
syn::Type::Slice(_) => {
10871091
// Option<[]> always implies that we want to treat len() == 0 differently from
10881092
// None, so we always map an Option<[]> into a pointer.
10891093
write!(w, " == std::ptr::null_mut()").unwrap();
1090-
true
1094+
(true, true)
10911095
},
10921096
_ => unimplemented!(),
10931097
}
@@ -1698,7 +1702,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
16981702
if single_ident_generic_path_to_ident(&p_arg.path).is_some() {
16991703
if self.crate_types.opaques.get(&resolved).is_some() {
17001704
write!(w, "crate::{}", resolved).unwrap();
1701-
} else { unimplemented!(); }
1705+
} else {
1706+
let cty = self.c_type_from_path(&resolved, true, true).expect("Template generics should be opaque or have a predefined mapping");
1707+
w.write(cty.as_bytes()).unwrap();
1708+
}
17021709
} else { unimplemented!(); }
17031710
} else { unimplemented!(); }
17041711
} else if let syn::Type::Array(a_arg) = t {
@@ -1758,7 +1765,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
17581765
if self.c_type_has_inner_from_path(&subtype) {
17591766
if !self.write_c_path_intern(generics, w, &$p_arg.path, is_ref, is_mut, ptr_for_ref) { return false; }
17601767
} else {
1761-
if !self.write_c_path_intern(generics, w, &$p_arg.path, true, is_mut, true) { return false; }
1768+
// Option<T> needs to be converted to a *mut T, ie mut ptr-for-ref
1769+
if !self.write_c_path_intern(generics, w, &$p_arg.path, true, true, true) { return false; }
17621770
}
17631771
} else {
17641772
if $p_arg.path.segments.len() == 1 {

0 commit comments

Comments
 (0)