use std::env;
use std::fs::File;
use std::io::{Read, Write};
+use std::iter::FromIterator;
use std::process;
use proc_macro2::Span;
(s, i) => {
if let Some(supertrait) = types.crate_types.traits.get(s) {
let resolver = get_module_type_resolver!(s, types.crate_libs, types.crate_types);
- writeln!(w, "impl {} for {} {{", s, trait_name).unwrap();
+
+ // Blindly assume that the same imports where `supertrait` is defined are also
+ // imported here. This will almost certainly break at some point, but it should be
+ // a compilation failure when it does so.
+ write!(w, "impl").unwrap();
+ maybe_write_lifetime_generics(w, &supertrait.generics, types);
+ write!(w, " {}", s).unwrap();
+ maybe_write_generics(w, &supertrait.generics, types, false);
+ writeln!(w, " for {} {{", trait_name).unwrap();
+
impl_trait_for_c!(supertrait, format!(".{}", i), &resolver);
writeln!(w, "}}").unwrap();
} else {
'alias_impls: for (alias_resolved, arguments) in aliases {
let mut new_ty_generics = Vec::new();
+ let mut new_ty_bounds = Vec::new();
let mut need_generics = false;
let alias_resolver_override;
alias_module, &types.crate_types.lib_ast.modules.get(alias_module).unwrap().items);
&alias_resolver_override
} else { &types.types };/*.maybe_resolve_path(&alias, None).unwrap();*/
+ let mut where_clause = Some(syn::WhereClause {
+ where_token: syn::Token![where](Span::call_site()),
+ predicates: syn::punctuated::Punctuated::new()
+ });
for (idx, gen) in i.generics.params.iter().enumerate() {
match gen {
syn::GenericParam::Type(type_param) => {
if let syn::PathArguments::AngleBracketed(ref t) = &arguments {
assert!(idx < t.args.len());
if let syn::GenericArgument::Type(syn::Type::Path(p)) = &t.args[idx] {
- if let Some(generic_arg) = alias_resolver.maybe_resolve_path(&p.path, None) {
+ let generic_bound = types.maybe_resolve_path(&trait_bound.path, None)
+ .unwrap_or_else(|| format!("{}::{}", types.module_path, single_ident_generic_path_to_ident(&trait_bound.path).unwrap()));
+ if let Some(generic_arg) = alias_resolver.maybe_resolve_path(&p.path, None) {
new_ty_generics.push((type_param.ident.clone(), syn::Type::Path(p.clone())));
- let generic_bound = types.maybe_resolve_path(&trait_bound.path, None)
- .unwrap_or_else(|| format!("{}::{}", types.module_path, single_ident_generic_path_to_ident(&trait_bound.path).unwrap()));
if let Some(traits_impld) = types.crate_types.trait_impls.get(&generic_arg) {
for trait_impld in traits_impld {
if *trait_impld == generic_bound { continue 'bounds_check; }
continue 'alias_impls;
}
} else if gen_types.is_some() {
- new_ty_generics.push((type_param.ident.clone(),
- gen_types.as_ref().resolve_type(&syn::Type::Path(p.clone())).clone()));
+ let resp = types.maybe_resolve_path(&p.path, gen_types.as_ref());
+ if generic_bound == "core::ops::Deref" && resp.is_some() {
+ new_ty_bounds.push((type_param.ident.clone(),
+ string_path_to_syn_path("core::ops::Deref")));
+ let mut bounds = syn::punctuated::Punctuated::new();
+ bounds.push(syn::TypeParamBound::Trait(syn::TraitBound {
+ paren_token: None,
+ modifier: syn::TraitBoundModifier::None,
+ lifetimes: None,
+ path: string_path_to_syn_path(&types.resolve_path(&p.path, gen_types.as_ref())),
+ }));
+ let mut path = string_path_to_syn_path(&format!("{}::Target", type_param.ident));
+ path.leading_colon = None;
+ where_clause.as_mut().unwrap().predicates.push(syn::WherePredicate::Type(syn::PredicateType {
+ lifetimes: None,
+ bounded_ty: syn::Type::Path(syn::TypePath { qself: None, path }),
+ colon_token: syn::Token![:](Span::call_site()),
+ bounds,
+ }));
+ } else {
+ new_ty_generics.push((type_param.ident.clone(),
+ gen_types.as_ref().resolve_type(&syn::Type::Path(p.clone())).clone()));
+ }
need_generics = true;
} else {
unimplemented!();
let alias_generics = types.crate_types.opaques.get(&alias_resolved).unwrap().1;
// If we need generics on the alias, create impl generic bounds...
- assert_eq!(new_ty_generics.len(), i.generics.params.len());
+ assert_eq!(new_ty_generics.len() + new_ty_bounds.len(), i.generics.params.len());
let mut args = syn::punctuated::Punctuated::new();
for (ident, param) in new_ty_generics.drain(..) {
// TODO: We blindly assume that generics in the type alias and
default: Some(param),
}));
}
+ for (ident, param) in new_ty_bounds.drain(..) {
+ // TODO: We blindly assume that generics in the type alias and
+ // the aliased type have the same names, which we really shouldn't.
+ if alias_generics.params.iter().any(|generic|
+ if let syn::GenericParam::Type(t) = generic { t.ident == ident } else { false })
+ {
+ args.push(parse_quote!(#ident));
+ }
+ params.push(syn::GenericParam::Type(syn::TypeParam {
+ attrs: Vec::new(),
+ ident,
+ colon_token: Some(syn::token::Colon(Span::call_site())),
+ bounds: syn::punctuated::Punctuated::from_iter(
+ Some(syn::TypeParamBound::Trait(syn::TraitBound {
+ path: param, paren_token: None, lifetimes: None,
+ modifier: syn::TraitBoundModifier::None,
+ }))
+ ),
+ eq_token: None,
+ default: None,
+ }));
+ }
// ... and swap the last segment of the impl self_ty to use the generic bounds.
let mut res = alias.clone();
res.segments.last_mut().unwrap().arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
lt_token: None,
params,
gt_token: None,
- where_clause: None,
+ where_clause,
},
impl_token: syn::Token![impl](Span::call_site()),
items: i.items.clone(),
writeln_field_docs(w, &field.attrs, "\t\t", types, Some(&gen_types), &field.ty);
write!(w, "\t\t{}: ", field.ident.as_ref().unwrap()).unwrap();
write!(&mut constr, "{}{}: ", if idx != 0 { ", " } else { "" }, field.ident.as_ref().unwrap()).unwrap();
- types.write_c_type(w, &field.ty, Some(&gen_types), false);
- types.write_c_type(&mut constr, &field.ty, Some(&gen_types), false);
+ types.write_c_type(w, &field.ty, Some(&gen_types), true);
+ types.write_c_type(&mut constr, &field.ty, Some(&gen_types), true);
writeln!(w, ",").unwrap();
}
write!(w, "\t}}").unwrap();
} else if let syn::Fields::Unnamed(fields) = &var.fields {
if fields.unnamed.len() == 1 {
let mut empty_check = Vec::new();
- types.write_c_type(&mut empty_check, &fields.unnamed[0].ty, Some(&gen_types), false);
+ types.write_c_type(&mut empty_check, &fields.unnamed[0].ty, Some(&gen_types), true);
if empty_check.is_empty() {
empty_tuple_variant = true;
}
}
if !empty_tuple_variant {
needs_free = true;
- write!(w, "(").unwrap();
+ writeln!(w, "(").unwrap();
for (idx, field) in fields.unnamed.iter().enumerate() {
if export_status(&field.attrs) == ExportStatus::TestOnly { continue; }
+ writeln_field_docs(w, &field.attrs, "\t\t", types, Some(&gen_types), &field.ty);
+ write!(w, "\t\t").unwrap();
+ types.write_c_type(w, &field.ty, Some(&gen_types), true);
+
write!(&mut constr, "{}: ", ('a' as u8 + idx as u8) as char).unwrap();
- types.write_c_type(w, &field.ty, Some(&gen_types), false);
types.write_c_type(&mut constr, &field.ty, Some(&gen_types), false);
if idx != fields.unnamed.len() - 1 {
- write!(w, ",").unwrap();
+ writeln!(w, ",").unwrap();
write!(&mut constr, ",").unwrap();
}
}
} else if let syn::Fields::Unnamed(fields) = &var.fields {
if !empty_tuple_variant {
write!(&mut constr, "(").unwrap();
- for idx in 0..fields.unnamed.len() {
- write!(&mut constr, "{}, ", ('a' as u8 + idx as u8) as char).unwrap();
+ for (idx, field) in fields.unnamed.iter().enumerate() {
+ let mut ref_c_ty = Vec::new();
+ let mut nonref_c_ty = Vec::new();
+ types.write_c_type(&mut ref_c_ty, &field.ty, Some(&gen_types), false);
+ types.write_c_type(&mut nonref_c_ty, &field.ty, Some(&gen_types), true);
+
+ if ref_c_ty != nonref_c_ty {
+ // We blindly assume references in field types are always opaque types, and
+ // print out an opaque reference -> owned reference conversion here.
+ write!(&mut constr, "{} {{ inner: {}.inner, is_owned: false }}, ", String::from_utf8(nonref_c_ty).unwrap(), ('a' as u8 + idx as u8) as char).unwrap();
+ } else {
+ write!(&mut constr, "{}, ", ('a' as u8 + idx as u8) as char).unwrap();
+ }
}
writeln!(&mut constr, ")").unwrap();
} else {
writeln!(&mut constr, "}}").unwrap();
writeln!(w, ",").unwrap();
}
- writeln!(w, "}}\nuse {}::{} as native{};\nimpl {} {{", types.module_path, e.ident, e.ident, e.ident).unwrap();
+ writeln!(w, "}}\nuse {}::{} as {}Import;", types.module_path, e.ident, e.ident).unwrap();
+ write!(w, "pub(crate) type native{} = {}Import", e.ident, e.ident).unwrap();
+ maybe_write_generics(w, &e.generics, &types, true);
+ writeln!(w, ";\n\nimpl {} {{", e.ident).unwrap();
macro_rules! write_conv {
($fn_sig: expr, $to_c: expr, $ref: expr) => {
} else if let syn::Fields::Unnamed(fields) = &var.fields {
if fields.unnamed.len() == 1 {
let mut empty_check = Vec::new();
- types.write_c_type(&mut empty_check, &fields.unnamed[0].ty, Some(&gen_types), false);
+ types.write_c_type(&mut empty_check, &fields.unnamed[0].ty, Some(&gen_types), true);
if empty_check.is_empty() {
empty_tuple_variant = true;
}
let mut sink = ::std::io::sink();
let mut out: &mut dyn std::io::Write = if $ref { &mut sink } else { w };
let new_var = if $to_c {
- types.write_to_c_conversion_new_var(&mut out, $field_ident, &$field.ty, Some(&gen_types), false)
+ types.write_to_c_conversion_new_var(&mut out, $field_ident, &$field.ty, Some(&gen_types), true)
} else {
types.write_from_c_conversion_new_var(&mut out, $field_ident, &$field.ty, Some(&gen_types))
};
if new_var {
let nonref_ident = format_ident!("{}_nonref", $field_ident);
if $to_c {
- types.write_to_c_conversion_new_var(w, &nonref_ident, &$field.ty, Some(&gen_types), false);
+ types.write_to_c_conversion_new_var(w, &nonref_ident, &$field.ty, Some(&gen_types), true);
} else {
types.write_from_c_conversion_new_var(w, &nonref_ident, &$field.ty, Some(&gen_types));
}
($field: expr, $field_ident: expr) => { {
if export_status(&$field.attrs) == ExportStatus::TestOnly { continue; }
if $to_c {
- types.write_to_c_conversion_inline_prefix(w, &$field.ty, Some(&gen_types), false);
+ types.write_to_c_conversion_inline_prefix(w, &$field.ty, Some(&gen_types), true);
} else {
types.write_from_c_conversion_prefix(w, &$field.ty, Some(&gen_types));
}
write!(w, "{}{}", $field_ident,
if $ref { "_nonref" } else { "" }).unwrap();
if $to_c {
- types.write_to_c_conversion_inline_suffix(w, &$field.ty, Some(&gen_types), false);
+ types.write_to_c_conversion_inline_suffix(w, &$field.ty, Some(&gen_types), true);
} else {
types.write_from_c_conversion_suffix(w, &$field.ty, Some(&gen_types));
}