/// 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) {
- let mut gen_types = GenericTypes::new();
+ let mut gen_types = GenericTypes::new(None);
assert!(gen_types.learn_generics(generics, types));
if !generics.params.is_empty() {
write!(w, "<").unwrap();
}
writeln_docs(w, &t.attrs, "");
- let mut gen_types = GenericTypes::new();
+ let mut gen_types = GenericTypes::new(None);
assert!(gen_types.learn_generics(&t.generics, types));
gen_types.learn_associated_types(&t, types);
writeln_opaque(w, &s.ident, struct_name, &s.generics, &s.attrs, types, extra_headers, cpp_headers);
if let syn::Fields::Named(fields) = &s.fields {
- let mut gen_types = GenericTypes::new();
+ let mut self_path_segs = syn::punctuated::Punctuated::new();
+ self_path_segs.push(s.ident.clone().into());
+ let self_path = syn::Path { leading_colon: None, segments: self_path_segs};
+ let mut gen_types = GenericTypes::new(Some((types.resolve_path(&self_path, None), &self_path)));
assert!(gen_types.learn_generics(&s.generics, types));
let mut all_fields_settable = true;
if let syn::Type::Tuple(_) = &*i.self_ty {
if types.understood_c_type(&*i.self_ty, None) {
- let mut gen_types = GenericTypes::new();
+ let mut gen_types = GenericTypes::new(None);
if !gen_types.learn_generics(&i.generics, types) {
eprintln!("Not implementing anything for `impl (..)` due to not understood generics");
return;
if p.qself.is_some() { unimplemented!(); }
if let Some(ident) = single_ident_generic_path_to_ident(&p.path) {
if let Some(resolved_path) = types.maybe_resolve_non_ignored_ident(&ident) {
- let mut gen_types = GenericTypes::new();
+ let mut gen_types = GenericTypes::new(Some((resolved_path.clone(), &p.path)));
if !gen_types.learn_generics(&i.generics, types) {
eprintln!("Not implementing anything for impl {} due to not understood generics", ident);
return;
}
writeln_docs(w, &f.attrs, "");
- let mut gen_types = GenericTypes::new();
+ let mut gen_types = GenericTypes::new(None);
if !gen_types.learn_generics(&f.sig.generics, types) { return; }
write!(w, "#[no_mangle]\npub extern \"C\" fn {}(", f.sig.ident).unwrap();
/// concrete C container struct, etc).
#[must_use]
pub struct GenericTypes<'a, 'b> {
+ self_ty: Option<(String, &'a syn::Path)>,
parent: Option<&'b GenericTypes<'b, 'b>>,
typed_generics: HashMap<&'a syn::Ident, (String, Option<&'a syn::Path>)>,
}
impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
- pub fn new() -> Self {
- Self { parent: None, typed_generics: HashMap::new(), }
+ pub fn new(self_ty: Option<(String, &'a syn::Path)>) -> Self {
+ Self { self_ty, parent: None, typed_generics: HashMap::new(), }
}
/// push a new context onto the stack, allowing for a new set of generics to be learned which
/// will override any lower contexts, but which will still fall back to resoltion via lower
/// contexts.
pub fn push_ctx<'c>(&'c self) -> GenericTypes<'a, 'c> {
- GenericTypes { parent: Some(self), typed_generics: HashMap::new(), }
+ GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), }
}
/// Learn the generics in generics in the current context, given a TypeResolver.
/// Attempt to resolve an Ident as a generic parameter and return the full path.
pub fn maybe_resolve_ident<'b>(&'b self, ident: &syn::Ident) -> Option<&'b String> {
+ if let Some(ty) = &self.self_ty {
+ if format!("{}", ident) == "Self" {
+ return Some(&ty.0);
+ }
+ }
if let Some(res) = self.typed_generics.get(ident).map(|(a, _)| a) {
return Some(res);
}
/// and syn::Path.
pub fn maybe_resolve_path<'b>(&'b self, path: &syn::Path) -> Option<(&'b String, &'a syn::Path)> {
if let Some(ident) = path.get_ident() {
+ if let Some(ty) = &self.self_ty {
+ if format!("{}", ident) == "Self" {
+ return Some((&ty.0, ty.1));
+ }
+ }
if let Some(res) = self.typed_generics.get(ident).map(|(a, b)| (a, b.unwrap())) {
return Some(res);
}