Skip to content

Commit b560eca

Browse files
committed
Support converting From impls
We'd always intended to do this, but never got around to it, so might as well.
1 parent 6870f3f commit b560eca

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

c-bindings-gen/src/main.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,39 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
13931393
// instantiated.
13941394
return;
13951395
}
1396-
if path_matches_nongeneric(&trait_path.1, &["From"]) {
1396+
if path_matches_ignoring_generics(&trait_path.1, &["From"]) {
1397+
let from_ty;
1398+
if let syn::PathArguments::AngleBracketed(args) = &trait_path.1.segments.last().unwrap().arguments {
1399+
assert_eq!(args.args.len(), 1);
1400+
if let syn::GenericArgument::Type(ref ty) = &args.args[0] {
1401+
from_ty = ty;
1402+
} else {
1403+
panic!("From needs arguments?");
1404+
}
1405+
} else {
1406+
panic!("From needs arguments?");
1407+
}
1408+
let to_std = resolved_path.starts_with("core::") || resolved_path.starts_with("std::");
1409+
if !to_std && types.understood_c_type(&from_ty, Some(&gen_types)) {
1410+
if let syn::Type::Path(from_path) = &from_ty {
1411+
let mut from_resolved_bytes = Vec::new();
1412+
types.write_c_type(&mut from_resolved_bytes, from_ty, Some(&gen_types), true);
1413+
let from_resolved = String::from_utf8(from_resolved_bytes).unwrap();
1414+
let from_ty_ident = from_resolved.rsplit("::").next().unwrap();
1415+
writeln!(w, "#[no_mangle]").unwrap();
1416+
writeln!(w, "/// Build a {ident} from a {from_ty_ident}").unwrap();
1417+
writeln!(w, "pub extern \"C\" fn {ident}_from_{from_ty_ident}(f: {from_resolved}) -> crate::{resolved_path} {{").unwrap();
1418+
write!(w, "\tlet from_obj = ").unwrap();
1419+
types.write_from_c_conversion_prefix(w, from_ty, Some(&gen_types));
1420+
write!(w, "f").unwrap();
1421+
types.write_from_c_conversion_suffix(w, from_ty, Some(&gen_types));
1422+
write!(w, ";\n\t").unwrap();
1423+
types.write_to_c_conversion_inline_prefix(w, &*i.self_ty, Some(&gen_types), true);
1424+
write!(w, "({resolved_path}::from(from_obj))").unwrap();
1425+
types.write_to_c_conversion_inline_suffix(w, &*i.self_ty, Some(&gen_types), true);
1426+
writeln!(w, "\n}}").unwrap();
1427+
} else { panic!("wat {:?}", from_ty); }
1428+
}
13971429
} else if path_matches_nongeneric(&trait_path.1, &["Default"]) {
13981430
writeln!(w, "/// Creates a \"default\" {}. See struct and individual field documentaiton for details on which values are used.", ident).unwrap();
13991431
write!(w, "#[must_use]\n#[no_mangle]\npub extern \"C\" fn {}_default() -> {} {{\n", ident, ident).unwrap();

c-bindings-gen/src/types.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ pub fn single_ident_generic_path_to_ident(p: &syn::Path) -> Option<&syn::Ident>
5656
} else { None }
5757
}
5858

59+
pub fn path_matches_ignoring_generics(p: &syn::Path, exp: &[&str]) -> bool {
60+
if p.segments.len() != exp.len() { return false; }
61+
for (seg, e) in p.segments.iter().zip(exp.iter()) {
62+
if &format!("{}", seg.ident) != *e { return false; }
63+
}
64+
true
65+
}
66+
5967
pub fn path_matches_nongeneric(p: &syn::Path, exp: &[&str]) -> bool {
6068
if p.segments.len() != exp.len() { return false; }
6169
for (seg, e) in p.segments.iter().zip(exp.iter()) {

0 commit comments

Comments
 (0)