+
+ macro_rules! impl_trait_for_c {
+ ($t: expr, $impl_accessor: expr, $type_resolver: expr, $generic_impls: expr) => {
+ let mut trait_gen_types = gen_types.push_ctx();
+ assert!(trait_gen_types.learn_generics_with_impls(&$t.generics, $generic_impls, $type_resolver));
+
+ let mut ref_types = HashSet::new();
+ for item in $t.items.iter() {
+ if let syn::TraitItem::Type(ref t) = &item {
+ if t.default.is_some() || t.generics.lt_token.is_some() { panic!("10"); }
+ let mut bounds_iter = t.bounds.iter();
+ loop {
+ match bounds_iter.next().unwrap() {
+ syn::TypeParamBound::Trait(tr) => {
+ match $type_resolver.resolve_path(&tr.path, None).as_str() {
+ "core::ops::Deref"|"core::ops::DerefMut"|"std::ops::Deref"|"std::ops::DerefMut" => {
+ // Handle cases like
+ // trait A {
+ // type B;
+ // type C: Deref<Target = Self::B>;
+ // }
+ // by tracking if we have any B's here and making them
+ // the *Ref types below.
+ if let syn::PathArguments::AngleBracketed(args) = &tr.path.segments.iter().last().unwrap().arguments {
+ if let syn::GenericArgument::Binding(bind) = args.args.iter().last().unwrap() {
+ assert_eq!(format!("{}", bind.ident), "Target");
+ if let syn::Type::Path(p) = &bind.ty {
+ assert!(p.qself.is_none());
+ let mut segs = p.path.segments.iter();
+ assert_eq!(format!("{}", segs.next().unwrap().ident), "Self");
+ ref_types.insert(format!("{}", segs.next().unwrap().ident));
+ assert!(segs.next().is_none());
+ } else { panic!(); }
+ }
+ }
+ },
+ _ => {},
+ }
+ break;
+ }
+ syn::TypeParamBound::Lifetime(_) => {},
+ }
+ }
+ }
+ }
+
+ for item in $t.items.iter() {
+ match item {
+ syn::TraitItem::Method(m) => {
+ if let ExportStatus::TestOnly = export_status(&m.attrs) { continue; }
+ if m.sig.constness.is_some() || m.sig.asyncness.is_some() || m.sig.unsafety.is_some() ||
+ m.sig.abi.is_some() || m.sig.variadic.is_some() {
+ panic!("1");
+ }
+ let mut meth_gen_types = trait_gen_types.push_ctx();
+ assert!(meth_gen_types.learn_generics(&m.sig.generics, $type_resolver));
+ // Note that we do *not* use the method generics when printing "native"
+ // rust parts - if the method is generic, we need to print a generic
+ // method.
+ write!(w, "\tfn {}", m.sig.ident).unwrap();
+ $type_resolver.write_rust_generic_param(w, Some(&gen_types), m.sig.generics.params.iter());
+ write!(w, "(").unwrap();
+ for inp in m.sig.inputs.iter() {
+ match inp {
+ syn::FnArg::Receiver(recv) => {
+ if !recv.attrs.is_empty() || recv.reference.is_none() { panic!("2"); }
+ write!(w, "&").unwrap();
+ if let Some(lft) = &recv.reference.as_ref().unwrap().1 {
+ write!(w, "'{} ", lft.ident).unwrap();
+ }
+ if recv.mutability.is_some() {
+ write!(w, "mut self").unwrap();
+ } else {
+ write!(w, "self").unwrap();
+ }
+ },
+ syn::FnArg::Typed(arg) => {
+ if !arg.attrs.is_empty() { panic!("3"); }
+ match &*arg.pat {
+ syn::Pat::Ident(ident) => {
+ if !ident.attrs.is_empty() || ident.by_ref.is_some() ||
+ ident.mutability.is_some() || ident.subpat.is_some() {
+ panic!("4");
+ }
+ write!(w, ", mut {}{}: ", if $type_resolver.skip_arg(&*arg.ty, Some(&meth_gen_types)) { "_" } else { "" }, ident.ident).unwrap();
+ }
+ _ => panic!("5"),
+ }
+ $type_resolver.write_rust_type(w, Some(&gen_types), &*arg.ty, false);
+ }
+ }
+ }
+ write!(w, ")").unwrap();
+ match &m.sig.output {
+ syn::ReturnType::Type(_, rtype) => {
+ write!(w, " -> ").unwrap();
+ $type_resolver.write_rust_type(w, Some(&gen_types), &*rtype, false)
+ },
+ _ => {},
+ }
+ write!(w, " {{\n\t\t").unwrap();
+ match export_status(&m.attrs) {
+ ExportStatus::NoExport => {
+ panic!("6");
+ },
+ _ => {},
+ }
+ if let syn::ReturnType::Type(_, rtype) = &m.sig.output {
+ if let syn::Type::Reference(r) = &**rtype {
+ assert_eq!(m.sig.inputs.len(), 1); // Must only take self!
+ writeln!(w, "if let Some(f) = self{}.set_{} {{", $impl_accessor, m.sig.ident).unwrap();
+ 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, "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;
+ }
+ }
+ write_method_var_decl_body(w, &m.sig, "\t", $type_resolver, Some(&meth_gen_types), true);
+ write!(w, "(self{}.{})(", $impl_accessor, m.sig.ident).unwrap();
+ let mut args = Vec::new();
+ write_method_call_params(&mut args, &m.sig, "\t", $type_resolver, Some(&meth_gen_types), "", true);
+ w.write_all(String::from_utf8(args).unwrap().replace("self", &format!("self{}", $impl_accessor)).as_bytes()).unwrap();
+
+ writeln!(w, "\n\t}}").unwrap();
+ },
+ &syn::TraitItem::Type(ref t) => {
+ if t.default.is_some() || t.generics.lt_token.is_some() { panic!("10"); }
+ let mut bounds_iter = t.bounds.iter();
+ loop {
+ match bounds_iter.next().unwrap() {
+ syn::TypeParamBound::Trait(tr) => {
+ write!(w, "\ttype {} = crate::{}", t.ident, $type_resolver.resolve_path(&tr.path, Some(&gen_types))).unwrap();
+ if ref_types.contains(&format!("{}", t.ident)) {
+ write!(w, "Ref").unwrap();
+ }
+ writeln!(w, ";").unwrap();
+ for bound in bounds_iter {
+ 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;
+ },
+ syn::TypeParamBound::Lifetime(_) => {},
+ }
+ }
+ },
+ _ => panic!("12"),
+ }
+ }
+ }
+ }
+
+ writeln!(w, "unsafe impl Send for {} {{}}", trait_name).unwrap();
+ writeln!(w, "unsafe impl Sync for {} {{}}", trait_name).unwrap();
+
+ writeln!(w, "#[allow(unused)]").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((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, pfx, field, sfx).unwrap();
+ } else {
+ writeln!(w, "\t\t{}: Clone::clone(&orig.{}),", field, field).unwrap();
+ }
+ }
+ writeln!(w, "\t}}\n}}").unwrap();
+