Skip to content

Commit 23a1d7a

Browse files
authored
Merge pull request #721 from TheBlueMatt/2020-09-649-bindings
Bindings Updates for #649
2 parents 3aa0253 + 5988789 commit 23a1d7a

29 files changed

+2649
-2565
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -170,18 +170,10 @@ jobs:
170170
# cbindgen's bindings output order can be FS-dependant, so check that the lines are all the same:
171171
mv lightning-c-bindings/include/lightning.h lightning-c-bindings/include/lightning.h.new
172172
git checkout lightning-c-bindings/include/lightning.h
173-
cat lightning-c-bindings/include/lightning.h | sort > lightning-c-bindings/include/lightning.h.sorted
174-
cat lightning-c-bindings/include/lightning.h.new | sort > lightning-c-bindings/include/lightning.h.new.sorted
173+
cat lightning-c-bindings/include/lightning.h | grep -v "Generated with cbindgen:[0-9\.]*" | sort > lightning-c-bindings/include/lightning.h.sorted
174+
cat lightning-c-bindings/include/lightning.h.new | grep -v "Generated with cbindgen:[0-9\.]*" | sort > lightning-c-bindings/include/lightning.h.new.sorted
175175
diff lightning-c-bindings/include/lightning.h.sorted lightning-c-bindings/include/lightning.h.new.sorted
176-
#
177-
mv lightning-c-bindings/include/lightningpp.hpp lightning-c-bindings/include/lightningpp.hpp.new
178-
git checkout lightning-c-bindings/include/lightningpp.hpp
179-
cat lightning-c-bindings/include/lightningpp.hpp | sort > lightning-c-bindings/include/lightningpp.hpp.sorted
180-
cat lightning-c-bindings/include/lightningpp.hpp.new | sort > lightning-c-bindings/include/lightningpp.hpp.new.sorted
181-
diff lightning-c-bindings/include/lightningpp.hpp.sorted lightning-c-bindings/include/lightningpp.hpp.new.sorted
182-
#
183176
[ "$(diff lightning-c-bindings/include/lightning.h.sorted lightning-c-bindings/include/lightning.h.new.sorted)" != "" ] && exit 2
184-
[ "$(diff lightning-c-bindings/include/lightningpp.hpp.sorted lightning-c-bindings/include/lightningpp.hpp.new.sorted)" != "" ] && exit 3
185177
git diff --exit-code
186178
fi
187179

c-bindings-gen/src/blocks.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,15 @@ pub fn write_method_params<W: std::io::Write>(w: &mut W, sig: &syn::Signature, a
113113
syn::FnArg::Typed(arg) => {
114114
if types.skip_arg(&*arg.ty, generics) { continue; }
115115
if !arg.attrs.is_empty() { unimplemented!(); }
116-
let mut is_ref = if let syn::Type::Reference(_) = *arg.ty { true } else { false };
117-
if let syn::Type::Reference(syn::TypeReference { ref elem, .. }) = *arg.ty {
118-
if let syn::Type::Slice(_) = &**elem {
119-
// Slices are mapped to non-ref Vec types, so we want them to be mut
120-
// letting us drain(..) the underlying Vec.
121-
is_ref = false;
122-
}
123-
}
116+
// First get the c type so that we can check if it ends up being a reference:
117+
let mut c_type = Vec::new();
118+
types.write_c_type(&mut c_type, &*arg.ty, generics, false);
124119
match &*arg.pat {
125120
syn::Pat::Ident(ident) => {
126121
if !ident.attrs.is_empty() || ident.subpat.is_some() {
127122
unimplemented!();
128123
}
129-
write!(w, "{}{}{}: ", if first_arg { "" } else { ", " }, if is_ref || !fn_decl { "" } else { "mut " }, ident.ident).unwrap();
124+
write!(w, "{}{}{}: ", if first_arg { "" } else { ", " }, if !fn_decl || c_type[0] == '&' as u8 || c_type[0] == '*' as u8 { "" } else { "mut " }, ident.ident).unwrap();
130125
first_arg = false;
131126
},
132127
syn::Pat::Wild(wild) => {
@@ -136,7 +131,7 @@ pub fn write_method_params<W: std::io::Write>(w: &mut W, sig: &syn::Signature, a
136131
},
137132
_ => unimplemented!(),
138133
}
139-
types.write_c_type(w, &*arg.ty, generics, false);
134+
w.write(&c_type).unwrap();
140135
}
141136
}
142137
}

c-bindings-gen/src/main.rs

Lines changed: 99 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn convert_macro<W: std::io::Write>(w: &mut W, macro_path: &syn::Path, stream: &
5656

5757
/// Convert "impl trait_path for for_obj { .. }" for manually-mapped types (ie (de)serialization)
5858
fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path, for_obj: &syn::Ident, types: &TypeResolver) {
59-
if let Some(t) = types.maybe_resolve_path(&trait_path) {
59+
if let Some(t) = types.maybe_resolve_path(&trait_path, None) {
6060
let s = types.maybe_resolve_ident(for_obj).unwrap();
6161
if !types.crate_types.opaques.get(&s).is_some() { return; }
6262
match &t as &str {
@@ -97,7 +97,7 @@ macro_rules! walk_supertraits { ($t: expr, $types: expr, ($( $pat: pat => $e: ex
9797
$( $pat => $e, )*
9898
}
9999
} else {
100-
let path = $types.resolve_path(&supertrait.path);
100+
let path = $types.resolve_path(&supertrait.path, None);
101101
match (&path as &str, &supertrait.path.segments.iter().last().unwrap().ident) {
102102
$( $pat => $e, )*
103103
}
@@ -357,7 +357,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
357357
let mut bounds_iter = t.bounds.iter();
358358
match bounds_iter.next().unwrap() {
359359
syn::TypeParamBound::Trait(tr) => {
360-
writeln!(w, "\ttype {} = crate::{};", t.ident, types.resolve_path(&tr.path)).unwrap();
360+
writeln!(w, "\ttype {} = crate::{};", t.ident, types.resolve_path(&tr.path, None)).unwrap();
361361
},
362362
_ => unimplemented!(),
363363
}
@@ -397,7 +397,7 @@ fn writeln_opaque<W: std::io::Write>(w: &mut W, ident: &syn::Ident, struct_name:
397397
writeln!(w, ";\n").unwrap();
398398
writeln!(extra_headers, "struct native{}Opaque;\ntypedef struct native{}Opaque LDKnative{};", ident, ident, ident).unwrap();
399399
writeln_docs(w, &attrs, "");
400-
writeln!(w, "#[must_use]\n#[repr(C)]\npub struct {} {{\n\t/// Nearly everyhwere, inner must be non-null, however in places where", struct_name).unwrap();
400+
writeln!(w, "#[must_use]\n#[repr(C)]\npub struct {} {{\n\t/// Nearly everywhere, inner must be non-null, however in places where", struct_name).unwrap();
401401
writeln!(w, "\t/// the Rust equivalent takes an Option, it may be set to null to indicate None.").unwrap();
402402
writeln!(w, "\tpub inner: *mut native{},\n\tpub is_owned: bool,\n}}\n", ident).unwrap();
403403
writeln!(w, "impl Drop for {} {{\n\tfn drop(&mut self) {{", struct_name).unwrap();
@@ -579,7 +579,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
579579
if let Some(trait_path) = i.trait_.as_ref() {
580580
if trait_path.0.is_some() { unimplemented!(); }
581581
if types.understood_c_path(&trait_path.1) {
582-
let full_trait_path = types.resolve_path(&trait_path.1);
582+
let full_trait_path = types.resolve_path(&trait_path.1, None);
583583
let trait_obj = *types.crate_types.traits.get(&full_trait_path).unwrap();
584584
// We learn the associated types maping from the original trait object.
585585
// That's great, except that they are unresolved idents, so if we learn
@@ -628,7 +628,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
628628
if let syn::ReturnType::Type(_, rtype) = &$m.sig.output {
629629
if let syn::Type::Reference(r) = &**rtype {
630630
write!(w, "\n\t\t{}{}: ", $indent, $m.sig.ident).unwrap();
631-
types.write_empty_rust_val(w, &*r.elem);
631+
types.write_empty_rust_val(Some(&gen_types), w, &*r.elem);
632632
writeln!(w, ",\n{}\t\tset_{}: Some({}_{}_set_{}),", $indent, $m.sig.ident, ident, trait_obj.ident, $m.sig.ident).unwrap();
633633
printed = true;
634634
}
@@ -722,7 +722,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
722722
writeln!(w, "\t// This is a bit race-y in the general case, but for our specific use-cases today, we're safe").unwrap();
723723
writeln!(w, "\t// Specifically, we must ensure that the first time we're called it can never be in parallel").unwrap();
724724
write!(w, "\tif ").unwrap();
725-
types.write_empty_rust_val_check(w, &*r.elem, &format!("trait_self_arg.{}", $m.sig.ident));
725+
types.write_empty_rust_val_check(Some(&gen_types), w, &*r.elem, &format!("trait_self_arg.{}", $m.sig.ident));
726726
writeln!(w, " {{").unwrap();
727727
writeln!(w, "\t\tunsafe {{ &mut *(trait_self_arg as *const {} as *mut {}) }}.{} = {}_{}_{}(trait_self_arg.this_arg);", trait_obj.ident, trait_obj.ident, $m.sig.ident, ident, trait_obj.ident, $m.sig.ident).unwrap();
728728
writeln!(w, "\t}}").unwrap();
@@ -1057,8 +1057,6 @@ struct FullLibraryAST {
10571057
/// `out_path` and fills it with wrapper structs/functions to allow calling the things in the AST
10581058
/// at `module` from C.
10591059
fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a>, in_dir: &str, out_dir: &str, path: &str, orig_crate: &str, module: &str, header_file: &mut File, cpp_header_file: &mut File) {
1060-
eprintln!("Converting {}...", path);
1061-
10621060
let syntax = if let Some(ast) = libast.files.get(module) { ast } else { return };
10631061

10641062
assert!(syntax.shebang.is_none()); // Not sure what this is, hope we dont have one
@@ -1096,6 +1094,8 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes
10961094
orig_crate, &new_mod, header_file, cpp_header_file);
10971095
}
10981096

1097+
eprintln!("Converting {} entries...", path);
1098+
10991099
let mut type_resolver = TypeResolver::new(orig_crate, module, crate_types);
11001100

11011101
for item in syntax.items.iter() {
@@ -1125,7 +1125,7 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes
11251125
// Re-export any primitive-type constants.
11261126
if let syn::Visibility::Public(_) = c.vis {
11271127
if let syn::Type::Path(p) = &*c.ty {
1128-
let resolved_path = type_resolver.resolve_path(&p.path);
1128+
let resolved_path = type_resolver.resolve_path(&p.path, None);
11291129
if type_resolver.is_primitive(&resolved_path) {
11301130
writeln!(out, "\n#[no_mangle]").unwrap();
11311131
writeln!(out, "pub static {}: {} = {}::{}::{};", c.ident, resolved_path, orig_crate, module, c.ident).unwrap();
@@ -1139,8 +1139,18 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes
11391139
ExportStatus::Export => {},
11401140
ExportStatus::NoExport|ExportStatus::TestOnly => continue,
11411141
}
1142-
if t.generics.lt_token.is_none() {
1143-
writeln_opaque(&mut out, &t.ident, &format!("{}", t.ident), &t.generics, &t.attrs, &type_resolver, header_file, cpp_header_file);
1142+
1143+
let mut process_alias = true;
1144+
for tok in t.generics.params.iter() {
1145+
if let syn::GenericParam::Lifetime(_) = tok {}
1146+
else { process_alias = false; }
1147+
}
1148+
if process_alias {
1149+
match &*t.ty {
1150+
syn::Type::Path(_) =>
1151+
writeln_opaque(&mut out, &t.ident, &format!("{}", t.ident), &t.generics, &t.attrs, &type_resolver, header_file, cpp_header_file),
1152+
_ => {}
1153+
}
11441154
}
11451155
}
11461156
},
@@ -1180,6 +1190,52 @@ fn load_ast(in_dir: &str, path: &str, module: String, ast_storage: &mut FullLibr
11801190
ast_storage.files.insert(module, syntax);
11811191
}
11821192

1193+
/// Insert ident -> absolute Path resolutions into imports from the given UseTree and path-prefix.
1194+
fn process_use_intern<'a>(u: &'a syn::UseTree, mut path: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2>, imports: &mut HashMap<&'a syn::Ident, syn::Path>) {
1195+
match u {
1196+
syn::UseTree::Path(p) => {
1197+
path.push(syn::PathSegment { ident: p.ident.clone(), arguments: syn::PathArguments::None });
1198+
process_use_intern(&p.tree, path, imports);
1199+
},
1200+
syn::UseTree::Name(n) => {
1201+
path.push(syn::PathSegment { ident: n.ident.clone(), arguments: syn::PathArguments::None });
1202+
imports.insert(&n.ident, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path });
1203+
},
1204+
syn::UseTree::Group(g) => {
1205+
for i in g.items.iter() {
1206+
process_use_intern(i, path.clone(), imports);
1207+
}
1208+
},
1209+
_ => {}
1210+
}
1211+
}
1212+
1213+
/// Map all the Paths in a Type into absolute paths given a set of imports (generated via process_use_intern)
1214+
fn resolve_imported_refs(imports: &HashMap<&syn::Ident, syn::Path>, mut ty: syn::Type) -> syn::Type {
1215+
match &mut ty {
1216+
syn::Type::Path(p) => {
1217+
if let Some(ident) = p.path.get_ident() {
1218+
if let Some(newpath) = imports.get(ident) {
1219+
p.path = newpath.clone();
1220+
}
1221+
} else { unimplemented!(); }
1222+
},
1223+
syn::Type::Reference(r) => {
1224+
r.elem = Box::new(resolve_imported_refs(imports, (*r.elem).clone()));
1225+
},
1226+
syn::Type::Slice(s) => {
1227+
s.elem = Box::new(resolve_imported_refs(imports, (*s.elem).clone()));
1228+
},
1229+
syn::Type::Tuple(t) => {
1230+
for e in t.elems.iter_mut() {
1231+
*e = resolve_imported_refs(imports, e.clone());
1232+
}
1233+
},
1234+
_ => unimplemented!(),
1235+
}
1236+
ty
1237+
}
1238+
11831239
/// Walk the FullLibraryAST, deciding how things will be mapped and adding tracking to CrateTypes.
11841240
fn walk_ast<'a>(in_dir: &str, path: &str, module: String, ast_storage: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a>) {
11851241
let syntax = if let Some(ast) = ast_storage.files.get(&module) { ast } else { return };
@@ -1189,8 +1245,13 @@ fn walk_ast<'a>(in_dir: &str, path: &str, module: String, ast_storage: &'a FullL
11891245
walk_ast(in_dir, &path, new_mod, ast_storage, crate_types);
11901246
}
11911247

1248+
let mut import_maps = HashMap::new();
1249+
11921250
for item in syntax.items.iter() {
11931251
match item {
1252+
syn::Item::Use(u) => {
1253+
process_use_intern(&u.tree, syn::punctuated::Punctuated::new(), &mut import_maps);
1254+
},
11941255
syn::Item::Struct(s) => {
11951256
if let syn::Visibility::Public(_) = s.vis {
11961257
match export_status(&s.attrs) {
@@ -1211,6 +1272,31 @@ fn walk_ast<'a>(in_dir: &str, path: &str, module: String, ast_storage: &'a FullL
12111272
crate_types.traits.insert(trait_path, &t);
12121273
}
12131274
},
1275+
syn::Item::Type(t) => {
1276+
if let syn::Visibility::Public(_) = t.vis {
1277+
match export_status(&t.attrs) {
1278+
ExportStatus::Export => {},
1279+
ExportStatus::NoExport|ExportStatus::TestOnly => continue,
1280+
}
1281+
let type_path = format!("{}::{}", module, t.ident);
1282+
let mut process_alias = true;
1283+
for tok in t.generics.params.iter() {
1284+
if let syn::GenericParam::Lifetime(_) = tok {}
1285+
else { process_alias = false; }
1286+
}
1287+
if process_alias {
1288+
match &*t.ty {
1289+
syn::Type::Path(_) => {
1290+
// If its a path with no generics, assume we don't map the aliased type and map it opaque
1291+
crate_types.opaques.insert(type_path, &t.ident);
1292+
},
1293+
_ => {
1294+
crate_types.type_aliases.insert(type_path, resolve_imported_refs(&import_maps, (*t.ty).clone()));
1295+
}
1296+
}
1297+
}
1298+
}
1299+
},
12141300
syn::Item::Enum(e) if is_enum_opaque(e) => {
12151301
if let syn::Visibility::Public(_) = e.vis {
12161302
match export_status(&e.attrs) {
@@ -1264,7 +1350,7 @@ fn main() {
12641350
// ...then walk the ASTs tracking what types we will map, and how, so that we can resolve them
12651351
// when parsing other file ASTs...
12661352
let mut libtypes = CrateTypes { traits: HashMap::new(), opaques: HashMap::new(), mirrored_enums: HashMap::new(),
1267-
templates_defined: HashMap::new(), template_file: &mut derived_templates };
1353+
type_aliases: HashMap::new(), templates_defined: HashMap::default(), template_file: &mut derived_templates };
12681354
walk_ast(&args[1], "/lib.rs", "".to_string(), &libast, &mut libtypes);
12691355

12701356
// ... finally, do the actual file conversion/mapping, writing out types as we go.

0 commit comments

Comments
 (0)