const DEFAULT_IMPORTS: &'static str = "
use alloc::str::FromStr;
+use alloc::string::String;
use core::ffi::c_void;
use core::convert::Infallible;
use bitcoin::hashes::Hash;
let mut for_obj_vec = Vec::new();
types.write_c_type(&mut for_obj_vec, for_ty, Some(generics), false);
full_obj_path = String::from_utf8(for_obj_vec).unwrap();
- assert!(full_obj_path.starts_with(TypeResolver::generated_container_path()));
+ if !full_obj_path.starts_with(TypeResolver::generated_container_path()) { return; }
for_obj = full_obj_path[TypeResolver::generated_container_path().len() + 2..].into();
}
// the Rust type and a flag to indicate whether deallocation needs to
// happen) as well as provide an Option<>al function pointer which is
// called when the trait method is called which allows updating on the fly.
- write!(w, "\tpub {}: ", m.sig.ident).unwrap();
- generated_fields.push((format!("{}", m.sig.ident), None, None));
+ write!(w, "\tpub {}: core::cell::UnsafeCell<", m.sig.ident).unwrap();
+ generated_fields.push((format!("{}", m.sig.ident), Some(("Clone::clone(unsafe { &*core::cell::UnsafeCell::get(".to_owned(), ")}).into()")), None));
types.write_c_type(w, &*r.elem, Some(&meth_gen_types), false);
- writeln!(w, ",").unwrap();
+ writeln!(w, ">,").unwrap();
writeln!(w, "\t/// Fill in the {} field as a reference to it will be given to Rust after this returns", m.sig.ident).unwrap();
writeln!(w, "\t/// Note that this takes a pointer to this object, not the this_ptr like other methods do").unwrap();
writeln!(w, "\t/// This function pointer may be NULL if {} is filled in when this object is created and never needs updating.", m.sig.ident).unwrap();
writeln!(extra_headers, "struct LDK{};", trait_name).unwrap();
continue;
}
- // Sadly, this currently doesn't do what we want, but it should be easy to get
- // cbindgen to support it. See https://github.com/eqrion/cbindgen/issues/531
- writeln!(w, "\t#[must_use]").unwrap();
}
let mut cpp_docs = Vec::new();
let is_clonable = types.is_clonable(s);
writeln!(w, "\tpub {}: crate::{},", i, s).unwrap();
(format!("{}", i), if !is_clonable {
- Some(format!("crate::{}_clone_fields", s))
+ Some((format!("crate::{}_clone_fields(", s), ")"))
} else { None }, None)
});
}
writeln!(w, "\t\t\t(f)(&self{});", $impl_accessor).unwrap();
write!(w, "\t\t}}\n\t\t").unwrap();
$type_resolver.write_from_c_conversion_to_ref_prefix(w, &*r.elem, Some(&meth_gen_types));
- write!(w, "self{}.{}", $impl_accessor, m.sig.ident).unwrap();
+ write!(w, "unsafe {{ &*self{}.{}.get() }}", $impl_accessor, m.sig.ident).unwrap();
$type_resolver.write_from_c_conversion_to_ref_suffix(w, &*r.elem, Some(&meth_gen_types));
writeln!(w, "\n\t}}").unwrap();
continue;
syn::TypeParamBound::Trait(tr) => {
writeln!(w, "\ttype {} = crate::{};", t.ident, $type_resolver.resolve_path(&tr.path, Some(&gen_types))).unwrap();
for bound in bounds_iter {
- if let syn::TypeParamBound::Trait(_) = bound { panic!("11"); }
+ if let syn::TypeParamBound::Trait(t) = bound {
+ // We only allow for `Sized` here.
+ assert_eq!(t.path.segments.len(), 1);
+ assert_eq!(format!("{}", t.path.segments[0].ident), "Sized");
+ }
}
break;
},
writeln!(w, "unsafe impl Send for {} {{}}", trait_name).unwrap();
writeln!(w, "unsafe impl Sync for {} {{}}", trait_name).unwrap();
- writeln!(w, "#[no_mangle]").unwrap();
- writeln!(w, "pub(crate) extern \"C\" fn {}_clone_fields(orig: &{}) -> {} {{", trait_name, trait_name, trait_name).unwrap();
+ writeln!(w, "pub(crate) fn {}_clone_fields(orig: &{}) -> {} {{", trait_name, trait_name, trait_name).unwrap();
writeln!(w, "\t{} {{", trait_name).unwrap();
writeln!(w, "\t\tthis_arg: orig.this_arg,").unwrap();
for (field, clone_fn, _) in generated_fields.iter() {
- if let Some(f) = clone_fn {
+ if let Some((pfx, sfx)) = clone_fn {
// If the field isn't clonable, blindly assume its a trait and hope for the best.
- writeln!(w, "\t\t{}: {}(&orig.{}),", field, f, field).unwrap();
+ writeln!(w, "\t\t{}: {}&orig.{}{},", field, pfx, field, sfx).unwrap();
} else {
writeln!(w, "\t\t{}: Clone::clone(&orig.{}),", field, field).unwrap();
}
writeln!(w, "// directly as a Deref trait in higher-level structs:").unwrap();
writeln!(w, "impl core::ops::Deref for {} {{\n\ttype Target = Self;", trait_name).unwrap();
writeln!(w, "\tfn deref(&self) -> &Self {{\n\t\tself\n\t}}\n}}").unwrap();
+ writeln!(w, "impl core::ops::DerefMut for {} {{", trait_name).unwrap();
+ writeln!(w, "\tfn deref_mut(&mut self) -> &mut Self {{\n\t\tself\n\t}}\n}}").unwrap();
}
writeln!(w, "/// Calls the free function if one is set").unwrap();
define_field!(('a' as u8 + idx as u8) as char, ('0' as u8 + idx as u8) as char, field);
}
}
- _ => unimplemented!()
+ syn::Fields::Unit => {},
}
if all_fields_settable {
// Build a constructor!
writeln!(w, "/// Constructs a new {} given each field", struct_name).unwrap();
+ match &s.fields {
+ syn::Fields::Named(fields) => {
+ writeln_arg_docs(w, &[], "", types, Some(&gen_types),
+ fields.named.iter().map(|field| (format!("{}_arg", field.ident.as_ref().unwrap()), &field.ty)),
+ None);
+ },
+ syn::Fields::Unnamed(fields) => {
+ writeln_arg_docs(w, &[], "", types, Some(&gen_types),
+ fields.unnamed.iter().enumerate().map(|(idx, field)| (format!("{}_arg", ('a' as u8 + idx as u8)), &field.ty)),
+ None);
+ },
+ syn::Fields::Unit => {},
+ }
write!(w, "#[must_use]\n#[no_mangle]\npub extern \"C\" fn {}_new(", struct_name).unwrap();
match &s.fields {
types.write_c_type(w, &field.ty, Some(&gen_types), false);
}
}
- _ => unreachable!()
+ syn::Fields::Unit => {},
}
write!(w, ") -> {} {{\n\t", struct_name).unwrap();
match &s.fields {
}
}
},
- _ => unreachable!()
+ syn::Fields::Unit => {},
}
write!(w, "{} {{ inner: ObjOps::heap_alloc(", struct_name).unwrap();
match &s.fields {
}
write!(w, "\t)").unwrap();
},
- _ => unreachable!()
+ syn::Fields::Unit => write!(w, "{}::{} {{}}", types.module_path, struct_name).unwrap(),
}
writeln!(w, "), is_owned: true }}\n}}").unwrap();
}
if i.defaultness.is_some() || i.unsafety.is_some() { unimplemented!(); }
if let Some(trait_path) = i.trait_.as_ref() {
if trait_path.0.is_some() { unimplemented!(); }
- if types.understood_c_path(&trait_path.1) {
- let full_trait_path = types.resolve_path(&trait_path.1, None);
- let trait_obj = *types.crate_types.traits.get(&full_trait_path).unwrap();
+ let full_trait_path_opt = types.maybe_resolve_path(&trait_path.1, None);
+ let trait_obj_opt = full_trait_path_opt.as_ref().and_then(|path| types.crate_types.traits.get(path));
+ if types.understood_c_path(&trait_path.1) && trait_obj_opt.is_some() {
+ let full_trait_path = full_trait_path_opt.unwrap();
+ let trait_obj = *trait_obj_opt.unwrap();
let supertrait_name;
let supertrait_resolver;
if let syn::Type::Reference(r) = &**rtype {
write!(w, "\n\t\t{}{}: ", $indent, $m.sig.ident).unwrap();
types.write_empty_rust_val(Some(&gen_types), w, &*r.elem);
- writeln!(w, ",\n{}\t\tset_{}: Some({}_{}_set_{}),", $indent, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
+ writeln!(w, ".into(),\n{}\t\tset_{}: Some({}_{}_set_{}),", $indent, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
printed = true;
}
}
writeln!(w, "\t// This is a bit race-y in the general case, but for our specific use-cases today, we're safe").unwrap();
writeln!(w, "\t// Specifically, we must ensure that the first time we're called it can never be in parallel").unwrap();
write!(w, "\tif ").unwrap();
- $types.write_empty_rust_val_check(Some(&meth_gen_types), w, &*r.elem, &format!("trait_self_arg.{}", $m.sig.ident));
+ $types.write_empty_rust_val_check(Some(&meth_gen_types), w, &*r.elem, &format!("unsafe {{ &*trait_self_arg.{}.get() }}", $m.sig.ident));
writeln!(w, " {{").unwrap();
- writeln!(w, "\t\tunsafe {{ &mut *(trait_self_arg as *const {} as *mut {}) }}.{} = {}_{}_{}(trait_self_arg.this_arg);", $trait.ident, $trait.ident, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
+ writeln!(w, "\t\t*unsafe {{ &mut *(&*(trait_self_arg as *const {})).{}.get() }} = {}_{}_{}(trait_self_arg.this_arg).into();", $trait.ident, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
writeln!(w, "\t}}").unwrap();
writeln!(w, "}}").unwrap();
}
writeln!(w, " {{ true }} else {{ false }}\n}}").unwrap();
} else if path_matches_nongeneric(&trait_path.1, &["core", "hash", "Hash"]) {
- writeln!(w, "/// Checks if two {}s contain equal inner contents.", ident).unwrap();
+ writeln!(w, "/// Generates a non-cryptographic 64-bit hash of the {}.", ident).unwrap();
write!(w, "#[no_mangle]\npub extern \"C\" fn {}_hash(o: &{}) -> u64 {{\n", ident, ident).unwrap();
if types.c_type_has_inner_from_path(&resolved_path) {
write!(w, "\tif o.inner.is_null() {{ return 0; }}\n").unwrap();
if let Some(trait_path) = i.trait_.as_ref() {
if let Some(tp) = import_resolver.maybe_resolve_path(&trait_path.1, None) {
if let Some(sp) = import_resolver.maybe_resolve_path(&p.path, None) {
- match crate_types.trait_impls.entry(sp) {
- hash_map::Entry::Occupied(mut e) => { e.get_mut().push(tp); },
- hash_map::Entry::Vacant(e) => { e.insert(vec![tp]); },
+ match crate_types.trait_impls.entry(sp.clone()) {
+ hash_map::Entry::Occupied(mut e) => { e.get_mut().push(tp.clone()); },
+ hash_map::Entry::Vacant(e) => { e.insert(vec![tp.clone()]); },
+ }
+ match crate_types.traits_impld.entry(tp) {
+ hash_map::Entry::Occupied(mut e) => { e.get_mut().push(sp); },
+ hash_map::Entry::Vacant(e) => { e.insert(vec![sp]); },
}
}
}
}
if let Some(tp) = import_resolver.maybe_resolve_path(&trait_path.1, None) {
if let Some(sp) = import_resolver.maybe_resolve_path(&p.path, None) {
- match crate_types.trait_impls.entry(sp) {
- hash_map::Entry::Occupied(mut e) => { e.get_mut().push(tp); },
- hash_map::Entry::Vacant(e) => { e.insert(vec![tp]); },
+ match crate_types.trait_impls.entry(sp.clone()) {
+ hash_map::Entry::Occupied(mut e) => { e.get_mut().push(tp.clone()); },
+ hash_map::Entry::Vacant(e) => { e.insert(vec![tp.clone()]); },
+ }
+ match crate_types.traits_impld.entry(tp) {
+ hash_map::Entry::Occupied(mut e) => { e.get_mut().push(sp); },
+ hash_map::Entry::Vacant(e) => { e.insert(vec![sp]); },
}
}
}