writeln!(w, "impl Drop for {} {{", mangled_container).unwrap();
writeln!(w, "\tfn drop(&mut self) {{").unwrap();
writeln!(w, "\t\tif self.datalen == 0 {{ return; }}").unwrap();
- writeln!(w, "\t\tunsafe {{ Box::from_raw(core::slice::from_raw_parts_mut(self.data, self.datalen)) }};").unwrap();
+ writeln!(w, "\t\tlet _ = unsafe {{ Box::from_raw(core::slice::from_raw_parts_mut(self.data, self.datalen)) }};").unwrap();
writeln!(w, "\t}}").unwrap();
writeln!(w, "}}").unwrap();
if clonable {
match token_iter.next().unwrap() {
TokenTree::Literal(lit) => {
// Drop the first and last chars from lit as they are always "
- let doc = format!("{}", lit);
+ let doc = format!("{}", lit).trim().replace("\n", &format!("\n{}//!", prefix));
writeln!(w, "{}//!{}", prefix, &doc[1..doc.len() - 1]).unwrap();
},
_ => unimplemented!(),
match token_iter.next().unwrap() {
TokenTree::Literal(lit) => {
// Drop the first and last chars from lit as they are always "
- let doc = format!("{}", lit);
+ let doc = format!("{}", lit).trim().replace("\n", &format!("\n{}///", prefix));
writeln!(w, "{}///{}", prefix, &doc[1..doc.len() - 1]).unwrap();
},
_ => unimplemented!(),
},
}
}
- if let Some((types, generics, inp, outp, field)) = method_args_ret {
+ if let Some((types, generics, inp, outp, field_ty)) = method_args_ret {
let mut nullable_found = false;
for (name, inp) in inp {
if types.skip_arg(inp, generics) { continue; }
nullable_found = true;
writeln!(w, "{}/// Note that the return value (or a relevant inner pointer) may be NULL or all-0s to represent None", prefix).unwrap();
}
+ let field = field_ty.map(|ty| generics.resolve_type(ty));
if if let Some(syn::Type::Reference(syn::TypeReference { elem, .. })) = field {
if let syn::Type::Path(syn::TypePath { ref path, .. }) = &**elem {
+ let resolved_path = types.resolve_path(path, generics);
+ if types.crate_types.opaques.get(&resolved_path).is_some() {
+ writeln!(w, "{}/// Note that this field is expected to be a reference.", prefix).unwrap();
+ }
types.is_path_transparent_container(path, generics, true)
} else { false }
} else if let Some(syn::Type::Path(syn::TypePath { ref path, .. })) = field {
/// this_param is used when returning Self or accepting a self parameter, and should be the
/// concrete, mapped type.
pub fn write_method_params<W: std::io::Write>(w: &mut W, sig: &syn::Signature, this_param: &str, types: &mut TypeResolver, generics: Option<&GenericTypes>, self_ptr: bool, fn_decl: bool) {
- if sig.constness.is_some() || sig.asyncness.is_some() || sig.unsafety.is_some() ||
+ if sig.asyncness.is_some() || sig.unsafety.is_some() ||
sig.abi.is_some() || sig.variadic.is_some() {
unimplemented!();
}
let mut first_arg = true;
let mut num_unused = 0;
for inp in sig.inputs.iter() {
+ let mut handle_self = |is_ref: bool, is_mut: bool| {
+ write!(w, "{}this_arg: {}{}", if !is_ref { "mut " } else { "" },
+ if is_ref {
+ match (self_ptr, is_mut) {
+ (true, true) => "*mut ",
+ (true, false) => "*const ",
+ (false, true) => "&mut ",
+ (false, false) => "&",
+ }
+ } else { "" }, this_param).unwrap();
+ assert!(first_arg);
+ first_arg = false;
+ };
match inp {
syn::FnArg::Receiver(recv) => {
if !recv.attrs.is_empty() { unimplemented!(); }
- write!(w, "{}this_arg: {}{}", if recv.reference.is_none() { "mut " } else { "" },
- if recv.reference.is_some() {
- match (self_ptr, recv.mutability.is_some()) {
- (true, true) => "*mut ",
- (true, false) => "*const ",
- (false, true) => "&mut ",
- (false, false) => "&",
- }
- } else { "" }, this_param).unwrap();
- assert!(first_arg);
- first_arg = false;
+ handle_self(recv.reference.is_some(), recv.mutability.is_some());
},
syn::FnArg::Typed(arg) => {
+ if let syn::Pat::Ident(id) = &*arg.pat {
+ if format!("{}", id.ident) == "self" {
+ handle_self(id.by_ref.is_some(), id.mutability.is_some());
+ continue;
+ }
+ }
+
if types.skip_arg(&*arg.ty, generics) { continue; }
if !arg.attrs.is_empty() { unimplemented!(); }
// First get the c type so that we can check if it ends up being a reference:
},
_ => unimplemented!(),
}
- w.write(&c_type).unwrap();
+ w.write_all(&c_type).unwrap();
}
}
}
write!(w, ")").unwrap();
match &sig.output {
syn::ReturnType::Type(_, rtype) => {
- write!(w, " -> ").unwrap();
- if let Some(mut remaining_path) = first_seg_self(&*rtype) {
- if remaining_path.next().is_none() {
- write!(w, "{}", this_param).unwrap();
- return;
+ let mut ret_ty = Vec::new();
+ types.write_c_type(&mut ret_ty, &*rtype, generics, true);
+
+ if !ret_ty.is_empty() {
+ write!(w, " -> ").unwrap();
+ if let Some(mut remaining_path) = first_seg_self(&*rtype) {
+ if remaining_path.next().is_none() {
+ write!(w, "{}", this_param).unwrap();
+ return;
+ }
}
+ w.write_all(&ret_ty).unwrap();
}
- types.write_c_type(w, &*rtype, generics, true);
},
_ => {},
}
match inp {
syn::FnArg::Receiver(_) => {},
syn::FnArg::Typed(arg) => {
+ if let syn::Pat::Ident(id) = &*arg.pat {
+ if format!("{}", id.ident) == "self" {
+ continue;
+ }
+ }
+
if types.skip_arg(&*arg.ty, generics) { continue; }
if !arg.attrs.is_empty() { unimplemented!(); }
macro_rules! write_new_var {
}
},
syn::FnArg::Typed(arg) => {
+ if let syn::Pat::Ident(id) = &*arg.pat {
+ if format!("{}", id.ident) == "self" {
+ if to_c {
+ if id.by_ref.is_none() && !matches!(&*arg.ty, syn::Type::Reference(_)) { unimplemented!(); }
+ write!(w, "self.this_arg").unwrap();
+ first_arg = false;
+ }
+ continue;
+ }
+ }
+
if types.skip_arg(&*arg.ty, generics) {
if !to_c {
if !first_arg {
/// Prints concrete generic parameters for a struct/trait/function, including the less-than and
/// greater-than symbols, if any generic parameters are defined.
-pub fn maybe_write_generics<W: std::io::Write>(w: &mut W, generics: &syn::Generics, types: &TypeResolver, concrete_lifetimes: bool) {
+pub fn maybe_write_generics<W: std::io::Write>(w: &mut W, generics: &syn::Generics, generics_impld: &syn::PathArguments, types: &TypeResolver, concrete_lifetimes: bool) {
+ maybe_write_generics_intern(w, generics, Some(generics_impld), types, concrete_lifetimes, false);
+}
+
+pub fn maybe_write_non_lifetime_generics<W: std::io::Write>(w: &mut W, generics: &syn::Generics, generics_impld: &syn::PathArguments, types: &TypeResolver) {
+ maybe_write_generics_intern(w, generics, Some(generics_impld), types, false, true);
+}
+
+pub fn maybe_write_type_non_lifetime_generics<W: std::io::Write>(w: &mut W, generics: &syn::Generics, types: &TypeResolver) {
+ maybe_write_generics_intern(w, generics, None, types, false, true);
+}
+
+fn maybe_write_generics_intern<W: std::io::Write>(w: &mut W, generics: &syn::Generics, generics_impld: Option<&syn::PathArguments>, types: &TypeResolver, concrete_lifetimes: bool, dummy_lifetimes: bool) {
let mut gen_types = GenericTypes::new(None);
assert!(gen_types.learn_generics(generics, types));
if generics.params.is_empty() { return; }
for (idx, generic) in generics.params.iter().enumerate() {
match generic {
syn::GenericParam::Type(type_param) => {
- write!(w, "{}", if idx != 0 { ", " } else { "" }).unwrap();
+ let mut out = Vec::new();
let type_ident = &type_param.ident;
- types.write_c_type_in_generic_param(w, &syn::parse_quote!(#type_ident), Some(&gen_types), false);
+ if types.understood_c_type(&syn::parse_quote!(#type_ident), Some(&gen_types)) {
+ types.write_c_type_in_generic_param(&mut out, &syn::parse_quote!(#type_ident), Some(&gen_types), false);
+ } else {
+ if let Some(syn::PathArguments::AngleBracketed(args)) = generics_impld {
+ if let syn::GenericArgument::Type(ty) = &args.args[idx] {
+ types.write_c_type_in_generic_param(&mut out, &ty, Some(&gen_types), false);
+ }
+ }
+ }
+ if !out.is_empty() {
+ write!(w, "{}, ", String::from_utf8(out).unwrap()).unwrap();
+ }
},
syn::GenericParam::Lifetime(lt) => {
- if concrete_lifetimes {
- write!(w, "'static").unwrap();
+ if dummy_lifetimes {
+ write!(w, "'_, ").unwrap();
+ } else if concrete_lifetimes {
+ write!(w, "'static, ").unwrap();
} else {
- write!(w, "{}'{}", if idx != 0 { ", " } else { "" }, lt.lifetime.ident).unwrap();
+ write!(w, "'{}, ", lt.lifetime.ident).unwrap();
}
},
_ => unimplemented!(),