Skip to content

Commit 1af6e34

Browse files
authored
Merge 9fe3124 into 8f10a1d
2 parents 8f10a1d + 9fe3124 commit 1af6e34

31 files changed

+1001
-233
lines changed

c-bindings-gen/src/main.rs

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
148148
}
149149
writeln_docs(w, &t.attrs, "");
150150

151+
let mut gen_types = GenericTypes::new();
152+
assert!(gen_types.learn_generics(&t.generics, types));
153+
151154
writeln!(w, "#[repr(C)]\npub struct {} {{", trait_name).unwrap();
152155
writeln!(w, "\tpub this_arg: *mut c_void,").unwrap();
153156
let associated_types = learn_associated_types(t);
@@ -158,15 +161,17 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
158161
match export_status(&m.attrs) {
159162
ExportStatus::NoExport => {
160163
// NoExport in this context means we'll hit an unimplemented!() at runtime,
161-
// so add a comment noting that this needs to change in the output.
162-
writeln!(w, "\t//XXX: Need to export {}", m.sig.ident).unwrap();
163-
continue;
164+
// so bail out.
165+
unimplemented!();
164166
},
165167
ExportStatus::Export => {},
166168
ExportStatus::TestOnly => continue,
167169
}
168170
if m.default.is_some() { unimplemented!(); }
169171

172+
gen_types.push_ctx();
173+
assert!(gen_types.learn_generics(&m.sig.generics, types));
174+
170175
writeln_docs(w, &m.attrs, "\t");
171176

172177
if let syn::ReturnType::Type(_, rtype) = &m.sig.output {
@@ -183,7 +188,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
183188
// called when the trait method is called which allows updating on the fly.
184189
write!(w, "\tpub {}: ", m.sig.ident).unwrap();
185190
generated_fields.push(format!("{}", m.sig.ident));
186-
types.write_c_type(w, &*r.elem, None, false);
191+
types.write_c_type(w, &*r.elem, Some(&gen_types), false);
187192
writeln!(w, ",").unwrap();
188193
writeln!(w, "\t/// Fill in the {} field as a reference to it will be given to Rust after this returns", m.sig.ident).unwrap();
189194
writeln!(w, "\t/// Note that this takes a pointer to this object, not the this_ptr like other methods do").unwrap();
@@ -195,6 +200,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
195200
// which does not compile since Thing is not defined before it is used.
196201
writeln!(extra_headers, "struct LDK{};", trait_name).unwrap();
197202
writeln!(extra_headers, "typedef struct LDK{} LDK{};", trait_name, trait_name).unwrap();
203+
gen_types.pop_ctx();
198204
continue;
199205
}
200206
// Sadly, this currently doesn't do what we want, but it should be easy to get
@@ -204,8 +210,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
204210

205211
write!(w, "\tpub {}: extern \"C\" fn (", m.sig.ident).unwrap();
206212
generated_fields.push(format!("{}", m.sig.ident));
207-
write_method_params(w, &m.sig, &associated_types, "c_void", types, None, true, false);
213+
write_method_params(w, &m.sig, &associated_types, "c_void", types, Some(&gen_types), true, false);
208214
writeln!(w, ",").unwrap();
215+
216+
gen_types.pop_ctx();
209217
},
210218
&syn::TraitItem::Type(_) => {},
211219
_ => unimplemented!(),
@@ -218,7 +226,8 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
218226
generated_fields.push("clone".to_owned());
219227
},
220228
("std::cmp::Eq", _) => {
221-
writeln!(w, "\tpub eq: extern \"C\" fn (this_arg: *const c_void, other_arg: *const c_void) -> bool,").unwrap();
229+
writeln!(w, "\tpub eq: extern \"C\" fn (this_arg: *const c_void, other_arg: &{}) -> bool,", trait_name).unwrap();
230+
writeln!(extra_headers, "typedef struct LDK{} LDK{};", trait_name, trait_name).unwrap();
222231
generated_fields.push("eq".to_owned());
223232
},
224233
("std::hash::Hash", _) => {
@@ -243,21 +252,25 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
243252
("std::cmp::Eq", _) => {
244253
writeln!(w, "impl std::cmp::Eq for {} {{}}", trait_name).unwrap();
245254
writeln!(w, "impl std::cmp::PartialEq for {} {{", trait_name).unwrap();
246-
writeln!(w, "\tfn eq(&self, o: &Self) -> bool {{ (self.eq)(self.this_arg, o.this_arg) }}\n}}").unwrap();
255+
writeln!(w, "\tfn eq(&self, o: &Self) -> bool {{ (self.eq)(self.this_arg, o) }}\n}}").unwrap();
247256
},
248257
("std::hash::Hash", _) => {
249258
writeln!(w, "impl std::hash::Hash for {} {{", trait_name).unwrap();
250259
writeln!(w, "\tfn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {{ hasher.write_u64((self.hash)(self.this_arg)) }}\n}}").unwrap();
251260
},
252261
("Clone", _) => {
253-
writeln!(w, "impl Clone for {} {{", trait_name).unwrap();
254-
writeln!(w, "\tfn clone(&self) -> Self {{").unwrap();
255-
writeln!(w, "\t\tSelf {{").unwrap();
256-
writeln!(w, "\t\tthis_arg: if let Some(f) = self.clone {{ (f)(self.this_arg) }} else {{ self.this_arg }},").unwrap();
262+
writeln!(w, "#[no_mangle]").unwrap();
263+
writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", trait_name, trait_name, trait_name).unwrap();
264+
writeln!(w, "\t{} {{", trait_name).unwrap();
265+
writeln!(w, "\t\tthis_arg: if let Some(f) = orig.clone {{ (f)(orig.this_arg) }} else {{ orig.this_arg }},").unwrap();
257266
for field in generated_fields.iter() {
258-
writeln!(w, "\t\t\t{}: self.{}.clone(),", field, field).unwrap();
267+
writeln!(w, "\t\t{}: orig.{}.clone(),", field, field).unwrap();
259268
}
260-
writeln!(w, "\t\t}}\n\t}}\n}}").unwrap();
269+
writeln!(w, "\t}}\n}}").unwrap();
270+
writeln!(w, "impl Clone for {} {{", trait_name).unwrap();
271+
writeln!(w, "\tfn clone(&self) -> Self {{").unwrap();
272+
writeln!(w, "\t\t{}_clone(self)", trait_name).unwrap();
273+
writeln!(w, "\t}}\n}}").unwrap();
261274
},
262275
(s, i) => {
263276
if s != "util::events::MessageSendEventsProvider" { unimplemented!(); }
@@ -284,8 +297,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
284297
m.sig.abi.is_some() || m.sig.variadic.is_some() {
285298
unimplemented!();
286299
}
300+
gen_types.push_ctx();
301+
assert!(gen_types.learn_generics(&m.sig.generics, types));
287302
write!(w, "\tfn {}", m.sig.ident).unwrap();
288-
types.write_rust_generic_param(w, m.sig.generics.params.iter());
303+
types.write_rust_generic_param(w, Some(&gen_types), m.sig.generics.params.iter());
289304
write!(w, "(").unwrap();
290305
for inp in m.sig.inputs.iter() {
291306
match inp {
@@ -309,27 +324,26 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
309324
ident.mutability.is_some() || ident.subpat.is_some() {
310325
unimplemented!();
311326
}
312-
write!(w, ", {}{}: ", if types.skip_arg(&*arg.ty, None) { "_" } else { "" }, ident.ident).unwrap();
327+
write!(w, ", {}{}: ", if types.skip_arg(&*arg.ty, Some(&gen_types)) { "_" } else { "" }, ident.ident).unwrap();
313328
}
314329
_ => unimplemented!(),
315330
}
316-
types.write_rust_type(w, &*arg.ty);
331+
types.write_rust_type(w, Some(&gen_types), &*arg.ty);
317332
}
318333
}
319334
}
320335
write!(w, ")").unwrap();
321336
match &m.sig.output {
322337
syn::ReturnType::Type(_, rtype) => {
323338
write!(w, " -> ").unwrap();
324-
types.write_rust_type(w, &*rtype)
339+
types.write_rust_type(w, Some(&gen_types), &*rtype)
325340
},
326341
_ => {},
327342
}
328343
write!(w, " {{\n\t\t").unwrap();
329344
match export_status(&m.attrs) {
330345
ExportStatus::NoExport => {
331-
writeln!(w, "unimplemented!();\n\t}}").unwrap();
332-
continue;
346+
unimplemented!();
333347
},
334348
_ => {},
335349
}
@@ -339,25 +353,27 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
339353
writeln!(w, "if let Some(f) = self.set_{} {{", m.sig.ident).unwrap();
340354
writeln!(w, "\t\t\t(f)(self);").unwrap();
341355
write!(w, "\t\t}}\n\t\t").unwrap();
342-
types.write_from_c_conversion_to_ref_prefix(w, &*r.elem, None);
356+
types.write_from_c_conversion_to_ref_prefix(w, &*r.elem, Some(&gen_types));
343357
write!(w, "self.{}", m.sig.ident).unwrap();
344-
types.write_from_c_conversion_to_ref_suffix(w, &*r.elem, None);
358+
types.write_from_c_conversion_to_ref_suffix(w, &*r.elem, Some(&gen_types));
345359
writeln!(w, "\n\t}}").unwrap();
360+
gen_types.pop_ctx();
346361
continue;
347362
}
348363
}
349-
write_method_var_decl_body(w, &m.sig, "\t", types, None, true);
364+
write_method_var_decl_body(w, &m.sig, "\t", types, Some(&gen_types), true);
350365
write!(w, "(self.{})(", m.sig.ident).unwrap();
351-
write_method_call_params(w, &m.sig, &associated_types, "\t", types, None, "", true);
366+
write_method_call_params(w, &m.sig, &associated_types, "\t", types, Some(&gen_types), "", true);
352367

353368
writeln!(w, "\n\t}}").unwrap();
369+
gen_types.pop_ctx();
354370
},
355371
&syn::TraitItem::Type(ref t) => {
356372
if t.default.is_some() || t.generics.lt_token.is_some() { unimplemented!(); }
357373
let mut bounds_iter = t.bounds.iter();
358374
match bounds_iter.next().unwrap() {
359375
syn::TypeParamBound::Trait(tr) => {
360-
writeln!(w, "\ttype {} = crate::{};", t.ident, types.resolve_path(&tr.path, None)).unwrap();
376+
writeln!(w, "\ttype {} = crate::{};", t.ident, types.resolve_path(&tr.path, Some(&gen_types))).unwrap();
361377
},
362378
_ => unimplemented!(),
363379
}
@@ -439,6 +455,10 @@ fn writeln_opaque<W: std::io::Write>(w: &mut W, ident: &syn::Ident, struct_name:
439455
writeln!(w, "pub(crate) extern \"C\" fn {}_clone_void(this_ptr: *const c_void) -> *mut c_void {{", struct_name).unwrap();
440456
writeln!(w, "\tBox::into_raw(Box::new(unsafe {{ (*(this_ptr as *mut native{})).clone() }})) as *mut c_void", struct_name).unwrap();
441457
writeln!(w, "}}").unwrap();
458+
writeln!(w, "#[no_mangle]").unwrap();
459+
writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", struct_name, struct_name, struct_name).unwrap();
460+
writeln!(w, "\t{} {{ inner: Box::into_raw(Box::new(unsafe {{ &*orig.inner }}.clone())), is_owned: true }}", struct_name).unwrap();
461+
writeln!(w, "}}").unwrap();
442462
break 'attr_loop;
443463
}
444464
}
@@ -980,6 +1000,10 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
9801000
if needs_free {
9811001
writeln!(w, "#[no_mangle]\npub extern \"C\" fn {}_free(this_ptr: {}) {{ }}", e.ident, e.ident).unwrap();
9821002
}
1003+
writeln!(w, "#[no_mangle]").unwrap();
1004+
writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", e.ident, e.ident, e.ident).unwrap();
1005+
writeln!(w, "\torig.clone()").unwrap();
1006+
writeln!(w, "}}").unwrap();
9831007
write_cpp_wrapper(cpp_headers, &format!("{}", e.ident), needs_free);
9841008
}
9851009

c-bindings-gen/src/types.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -932,19 +932,34 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
932932
// *** Original Rust Type Printing ***
933933
// ***********************************
934934

935-
fn write_rust_path<W: std::io::Write>(&self, w: &mut W, path: &syn::Path) {
936-
if let Some(resolved) = self.maybe_resolve_path(&path, None) {
935+
fn in_rust_prelude(resolved_path: &str) -> bool {
936+
match resolved_path {
937+
"Vec" => true,
938+
"Result" => true,
939+
"Option" => true,
940+
_ => false,
941+
}
942+
}
943+
944+
fn write_rust_path<W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, path: &syn::Path) {
945+
if let Some(resolved) = self.maybe_resolve_path(&path, generics_resolver) {
937946
if self.is_primitive(&resolved) {
938947
write!(w, "{}", path.get_ident().unwrap()).unwrap();
939948
} else {
940-
if resolved.starts_with("ln::") || resolved.starts_with("chain::") || resolved.starts_with("util::") {
941-
write!(w, "lightning::{}", resolved).unwrap();
949+
// TODO: We should have a generic "is from a dependency" check here instead of
950+
// checking for "bitcoin" explicitly.
951+
if resolved.starts_with("bitcoin::") || Self::in_rust_prelude(&resolved) {
952+
write!(w, "{}", resolved).unwrap();
953+
// If we're printing a generic argument, it needs to reference the crate, otherwise
954+
// the original crate:
955+
} else if self.maybe_resolve_path(&path, None).as_ref() == Some(&resolved) {
956+
write!(w, "{}::{}", self.orig_crate, resolved).unwrap();
942957
} else {
943-
write!(w, "{}", resolved).unwrap(); // XXX: Probably doens't work, get_ident().unwrap()
958+
write!(w, "crate::{}", resolved).unwrap();
944959
}
945960
}
946961
if let syn::PathArguments::AngleBracketed(args) = &path.segments.iter().last().unwrap().arguments {
947-
self.write_rust_generic_arg(w, args.args.iter());
962+
self.write_rust_generic_arg(w, generics_resolver, args.args.iter());
948963
}
949964
} else {
950965
if path.leading_colon.is_some() {
@@ -954,12 +969,12 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
954969
if idx != 0 { write!(w, "::").unwrap(); }
955970
write!(w, "{}", seg.ident).unwrap();
956971
if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
957-
self.write_rust_generic_arg(w, args.args.iter());
972+
self.write_rust_generic_arg(w, generics_resolver, args.args.iter());
958973
}
959974
}
960975
}
961976
}
962-
pub fn write_rust_generic_param<'b, W: std::io::Write>(&self, w: &mut W, generics: impl Iterator<Item=&'b syn::GenericParam>) {
977+
pub fn write_rust_generic_param<'b, W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, generics: impl Iterator<Item=&'b syn::GenericParam>) {
963978
let mut had_params = false;
964979
for (idx, arg) in generics.enumerate() {
965980
if idx != 0 { write!(w, ", ").unwrap(); } else { write!(w, "<").unwrap(); }
@@ -974,7 +989,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
974989
match bound {
975990
syn::TypeParamBound::Trait(tb) => {
976991
if tb.paren_token.is_some() || tb.lifetimes.is_some() { unimplemented!(); }
977-
self.write_rust_path(w, &tb.path);
992+
self.write_rust_path(w, generics_resolver, &tb.path);
978993
},
979994
_ => unimplemented!(),
980995
}
@@ -987,24 +1002,24 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
9871002
if had_params { write!(w, ">").unwrap(); }
9881003
}
9891004

990-
pub fn write_rust_generic_arg<'b, W: std::io::Write>(&self, w: &mut W, generics: impl Iterator<Item=&'b syn::GenericArgument>) {
1005+
pub fn write_rust_generic_arg<'b, W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, generics: impl Iterator<Item=&'b syn::GenericArgument>) {
9911006
write!(w, "<").unwrap();
9921007
for (idx, arg) in generics.enumerate() {
9931008
if idx != 0 { write!(w, ", ").unwrap(); }
9941009
match arg {
995-
syn::GenericArgument::Type(t) => self.write_rust_type(w, t),
1010+
syn::GenericArgument::Type(t) => self.write_rust_type(w, generics_resolver, t),
9961011
_ => unimplemented!(),
9971012
}
9981013
}
9991014
write!(w, ">").unwrap();
10001015
}
1001-
pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, t: &syn::Type) {
1016+
pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type) {
10021017
match t {
10031018
syn::Type::Path(p) => {
10041019
if p.qself.is_some() || p.path.leading_colon.is_some() {
10051020
unimplemented!();
10061021
}
1007-
self.write_rust_path(w, &p.path);
1022+
self.write_rust_path(w, generics, &p.path);
10081023
},
10091024
syn::Type::Reference(r) => {
10101025
write!(w, "&").unwrap();
@@ -1014,11 +1029,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
10141029
if r.mutability.is_some() {
10151030
write!(w, "mut ").unwrap();
10161031
}
1017-
self.write_rust_type(w, &*r.elem);
1032+
self.write_rust_type(w, generics, &*r.elem);
10181033
},
10191034
syn::Type::Array(a) => {
10201035
write!(w, "[").unwrap();
1021-
self.write_rust_type(w, &a.elem);
1036+
self.write_rust_type(w, generics, &a.elem);
10221037
if let syn::Expr::Lit(l) = &a.len {
10231038
if let syn::Lit::Int(i) = &l.lit {
10241039
write!(w, "; {}]", i).unwrap();
@@ -1027,14 +1042,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
10271042
}
10281043
syn::Type::Slice(s) => {
10291044
write!(w, "[").unwrap();
1030-
self.write_rust_type(w, &s.elem);
1045+
self.write_rust_type(w, generics, &s.elem);
10311046
write!(w, "]").unwrap();
10321047
},
10331048
syn::Type::Tuple(s) => {
10341049
write!(w, "(").unwrap();
10351050
for (idx, t) in s.elems.iter().enumerate() {
10361051
if idx != 0 { write!(w, ", ").unwrap(); }
1037-
self.write_rust_type(w, &t);
1052+
self.write_rust_type(w, generics, &t);
10381053
}
10391054
write!(w, ")").unwrap();
10401055
},
@@ -1743,7 +1758,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
17431758
} else if in_crate {
17441759
write!(w, "{}", c_type).unwrap();
17451760
} else {
1746-
self.write_rust_type(w, &t);
1761+
self.write_rust_type(w, None, &t);
17471762
}
17481763
} else {
17491764
// If we just write out resolved_generic, it may mostly work, however for

genbindings.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ else
167167
fi
168168

169169
# Now build with LTO on on both C++ and rust, but without cross-language LTO:
170-
cargo rustc -v --release -- -C lto
170+
CARGO_PROFILE_RELEASE_LTO=true cargo rustc -v --release -- -C lto
171171
clang++ -std=c++11 -Wall -flto -O2 -pthread demo.cpp target/release/libldk.a -ldl
172172
echo "C++ Bin size and runtime with only RL (LTO) optimized:"
173173
ls -lha a.out
@@ -179,7 +179,7 @@ if [ "$HOST_PLATFORM" != "host: x86_64-apple-darwin" -a "$CLANGPP" != "" ]; then
179179
# or Ubuntu packages). This should work fine on Distros which do more involved
180180
# packaging than simply shipping the rustup binaries (eg Debian should Just Work
181181
# here).
182-
cargo rustc -v --release -- -C linker-plugin-lto -C lto -C link-arg=-fuse-ld=lld
182+
CARGO_PROFILE_RELEASE_LTO=true cargo rustc -v --release -- -C linker-plugin-lto -C lto -C link-arg=-fuse-ld=lld
183183
$CLANGPP -Wall -std=c++11 -flto -fuse-ld=lld -O2 -pthread demo.cpp target/release/libldk.a -ldl
184184
echo "C++ Bin size and runtime with cross-language LTO:"
185185
ls -lha a.out

0 commit comments

Comments
 (0)