self_ty: Option<(String, &'a syn::Path)>,
parent: Option<&'b GenericTypes<'b, 'b>>,
typed_generics: HashMap<&'a syn::Ident, (String, Option<&'a syn::Path>)>,
+ default_generics: HashMap<&'a syn::Ident, (&'a syn::Type, syn::Type)>,
}
impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
pub fn new(self_ty: Option<(String, &'a syn::Path)>) -> Self {
- Self { self_ty, parent: None, typed_generics: HashMap::new(), }
+ Self { self_ty, parent: None, typed_generics: HashMap::new(), default_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 { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), }
+ GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), default_generics: HashMap::new(), }
}
/// Learn the generics in generics in the current context, given a TypeResolver.
} else { return false; }
}
}
+ if let Some(default) = type_param.default.as_ref() {
+ assert!(type_param.bounds.is_empty());
+ self.default_generics.insert(&type_param.ident, (default, parse_quote!(&#default)));
+ }
},
_ => {},
}
None
}
}
+
/// Attempt to resolve a Path as a generic parameter and return the full path. as both a string
/// and syn::Path.
pub fn maybe_resolve_path<'b>(&'b self, path: &syn::Path) -> Option<(&'b String, &'a syn::Path)> {
}
}
+trait ResolveType<'a> { fn resolve_type(&'a self, ty: &'a syn::Type) -> &'a syn::Type; }
+impl<'a, 'b, 'c: 'a + 'b> ResolveType<'c> for Option<&GenericTypes<'a, 'b>> {
+ fn resolve_type(&'c self, ty: &'c syn::Type) -> &'c syn::Type {
+ if let Some(us) = self {
+ match ty {
+ syn::Type::Path(p) => {
+ if let Some(ident) = p.path.get_ident() {
+ if let Some((ty, _)) = us.default_generics.get(ident) {
+ return ty;
+ }
+ }
+ },
+ syn::Type::Reference(syn::TypeReference { elem, .. }) => {
+ if let syn::Type::Path(p) = &**elem {
+ if let Some(ident) = p.path.get_ident() {
+ if let Some((_, refty)) = us.default_generics.get(ident) {
+ return refty;
+ }
+ }
+ }
+ }
+ _ => {},
+ }
+ }
+ ty
+ }
+}
+
#[derive(Clone, PartialEq)]
// The type of declaration and the object itself
pub enum DeclType<'a> {
LP: Fn(&str, bool, bool) -> Option<String>, DL: Fn(&mut W, &DeclType, &str, bool, bool), SC: Fn(bool, Option<&str>) -> String>
(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool,
tupleconv: &str, prefix: bool, sliceconv: SC, path_lookup: LP, decl_lookup: DL) {
- match t {
+ match generics.resolve_type(t) {
syn::Type::Reference(r) => {
self.write_conversion_inline_intern(w, &*r.elem, generics, true, r.mutability.is_some(),
ptr_for_ref, tupleconv, prefix, sliceconv, path_lookup, decl_lookup);
} }
}
- match t {
+ match generics.resolve_type(t) {
syn::Type::Reference(r) => {
if let syn::Type::Slice(_) = &*r.elem {
self.write_conversion_new_var_intern(w, ident, var, &*r.elem, generics, is_ref, ptr_for_ref, to_c, path_lookup, container_lookup, var_prefix, var_suffix)
}
}
fn write_c_type_intern<W: std::io::Write>(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool {
- match t {
+ match generics.resolve_type(t) {
syn::Type::Path(p) => {
if p.qself.is_some() {
return false;