Skip to content

Commit ca2a879

Browse files
committed
[bindings] Support mapping slices which contain tuples (with refs)
New work upstream puts tuples in slices, which is a very reasonable thing to expect, however we don't know how to generate conversions for such objects. Making it more complicated, upstream changes also include references to things inside such slices, which requires special handling to avoid creating dangling references. This adds support for converting such objects, noting that slices need to be converted first into Vecs which own their underlying objects and then need to map any reference types into references.
1 parent 99cb6eb commit ca2a879

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

c-bindings-gen/src/types.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,33 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
12051205
if let syn::Type::Path(p) = &*r.elem {
12061206
write!(w, "{}", sliceconv(self.c_type_has_inner_from_path(&self.resolve_path(&p.path, generics)))).unwrap();
12071207
} else { unimplemented!(); }
1208+
} else if let syn::Type::Tuple(t) = &*s.elem {
1209+
assert!(!t.elems.is_empty());
1210+
if prefix {
1211+
write!(w, "&local_").unwrap();
1212+
} else {
1213+
let mut needs_map = false;
1214+
for e in t.elems.iter() {
1215+
if let syn::Type::Reference(_) = e {
1216+
needs_map = true;
1217+
}
1218+
}
1219+
if needs_map {
1220+
write!(w, ".iter().map(|(").unwrap();
1221+
for i in 0..t.elems.len() {
1222+
write!(w, "{}{}", if i != 0 { ", " } else { "" }, ('a' as u8 + i as u8) as char).unwrap();
1223+
}
1224+
write!(w, ")| (").unwrap();
1225+
for (idx, e) in t.elems.iter().enumerate() {
1226+
if let syn::Type::Reference(_) = e {
1227+
write!(w, "{}{}", if idx != 0 { ", " } else { "" }, (idx as u8 + 'a' as u8) as char).unwrap();
1228+
} else if let syn::Type::Path(_) = e {
1229+
write!(w, "{}*{}", if idx != 0 { ", " } else { "" }, (idx as u8 + 'a' as u8) as char).unwrap();
1230+
} else { unimplemented!(); }
1231+
}
1232+
write!(w, ")).collect::<Vec<_>>()[..]").unwrap();
1233+
}
1234+
}
12081235
} else { unimplemented!(); }
12091236
},
12101237
syn::Type::Tuple(t) => {
@@ -1491,6 +1518,24 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
14911518
is_ref = true;
14921519
convert_container!("Slice", 1, || tyref.iter());
14931520
unimplemented!("convert_container should return true as container_lookup should succeed for slices");
1521+
} else if let syn::Type::Tuple(t) = &*s.elem {
1522+
// When mapping into a temporary new var, we need to own all the underlying objects.
1523+
// Thus, we drop any references inside the tuple and convert with non-reference types.
1524+
let mut elems = syn::punctuated::Punctuated::new();
1525+
for elem in t.elems.iter() {
1526+
if let syn::Type::Reference(r) = elem {
1527+
elems.push((*r.elem).clone());
1528+
} else {
1529+
elems.push(elem.clone());
1530+
}
1531+
}
1532+
let ty = [syn::Type::Tuple(syn::TypeTuple {
1533+
paren_token: t.paren_token, elems
1534+
})];
1535+
is_ref = false;
1536+
ptr_for_ref = true;
1537+
convert_container!("Slice", 1, || ty.iter());
1538+
unimplemented!("convert_container should return true as container_lookup should succeed for slices");
14941539
} else { unimplemented!() }
14951540
},
14961541
syn::Type::Tuple(t) => {
@@ -1808,6 +1853,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
18081853
for elem in tuple.elems.iter() {
18091854
if let syn::Type::Path(p) = elem {
18101855
write_path!(p, Some(&mut mangled_tuple_type));
1856+
} else if let syn::Type::Reference(refelem) = elem {
1857+
if let syn::Type::Path(p) = &*refelem.elem {
1858+
write_path!(p, Some(&mut mangled_tuple_type));
1859+
} else { return false; }
18111860
} else { return false; }
18121861
}
18131862
write!(w, "Z").unwrap();
@@ -1963,6 +2012,17 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
19632012
self.check_create_container(generics, mangled_container, "Vec", vec![&*r.elem], false);
19642013
true
19652014
} else { false }
2015+
} else if let syn::Type::Tuple(_) = &*s.elem {
2016+
let mut args = syn::punctuated::Punctuated::new();
2017+
args.push(syn::GenericArgument::Type((*s.elem).clone()));
2018+
let mut segments = syn::punctuated::Punctuated::new();
2019+
segments.push(syn::PathSegment {
2020+
ident: syn::Ident::new("Vec", Span::call_site()),
2021+
arguments: syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
2022+
colon2_token: None, lt_token: syn::Token![<](Span::call_site()), args, gt_token: syn::Token![>](Span::call_site()),
2023+
})
2024+
});
2025+
self.write_c_type_intern(generics, w, &syn::Type::Path(syn::TypePath { qself: None, path: syn::Path { leading_colon: None, segments } }), false, is_mut, ptr_for_ref)
19662026
} else { false }
19672027
},
19682028
syn::Type::Tuple(t) => {

0 commit comments

Comments
 (0)