|
| 1 | +use syn::visit_mut::VisitMut; |
| 2 | +use syn::{ |
| 3 | + Error, Ident, ImplItem, ImplItemConst, ImplItemFn, ImplItemType, Item, ItemImpl, ItemTrait, |
| 4 | + Path, TraitItem, Type, Visibility, WherePredicate, |
| 5 | +}; |
| 6 | + |
| 7 | +use crate::parse_internal; |
| 8 | +use crate::visitors::RemoveSelfPathVisitor; |
| 9 | + |
| 10 | +pub struct ItemBlanketTrait { |
| 11 | + pub context_ident: Ident, |
| 12 | + pub item_trait: ItemTrait, |
| 13 | +} |
| 14 | + |
| 15 | +impl ItemBlanketTrait { |
| 16 | + pub fn to_items(&self) -> syn::Result<Vec<Item>> { |
| 17 | + let item_trait = self.item_trait.clone(); |
| 18 | + let item_impl = self.to_item_impl()?; |
| 19 | + |
| 20 | + Ok(vec![item_trait.into(), item_impl.into()]) |
| 21 | + } |
| 22 | + |
| 23 | + pub fn to_item_impl(&self) -> syn::Result<ItemImpl> { |
| 24 | + let context_ident = &self.context_ident; |
| 25 | + let mut item_trait = self.item_trait.clone(); |
| 26 | + |
| 27 | + let mut impl_items: Vec<ImplItem> = Vec::new(); |
| 28 | + |
| 29 | + let mut assoc_idents: Vec<Ident> = Vec::new(); |
| 30 | + let mut assoc_bounds: Vec<WherePredicate> = Vec::new(); |
| 31 | + |
| 32 | + for trait_item in item_trait.items.iter() { |
| 33 | + if let TraitItem::Type(trait_item_type) = trait_item { |
| 34 | + let item_type_ident = &trait_item_type.ident; |
| 35 | + assoc_idents.push(item_type_ident.clone()); |
| 36 | + } |
| 37 | + } |
| 38 | + |
| 39 | + RemoveSelfPathVisitor { |
| 40 | + assoc_idents: &assoc_idents, |
| 41 | + } |
| 42 | + .visit_item_trait_mut(&mut item_trait); |
| 43 | + |
| 44 | + for trait_item in item_trait.items.iter_mut() { |
| 45 | + match trait_item { |
| 46 | + TraitItem::Type(trait_item_type) => { |
| 47 | + trait_item_type.default.take(); |
| 48 | + |
| 49 | + let item_type_ident = &trait_item_type.ident; |
| 50 | + |
| 51 | + let type_impl = parse_internal! { |
| 52 | + #item_type_ident |
| 53 | + }; |
| 54 | + |
| 55 | + if !trait_item_type.bounds.is_empty() { |
| 56 | + let current_assoc_bounds = trait_item_type.bounds.clone(); |
| 57 | + |
| 58 | + assoc_bounds.push(parse_internal! { |
| 59 | + #item_type_ident : #current_assoc_bounds |
| 60 | + }); |
| 61 | + } |
| 62 | + |
| 63 | + let impl_item_type = ImplItemType { |
| 64 | + attrs: trait_item_type.attrs.clone(), |
| 65 | + vis: Visibility::Inherited, |
| 66 | + defaultness: None, |
| 67 | + type_token: trait_item_type.type_token, |
| 68 | + ident: trait_item_type.ident.clone(), |
| 69 | + generics: trait_item_type.generics.clone(), |
| 70 | + eq_token: Default::default(), |
| 71 | + ty: type_impl, |
| 72 | + semi_token: Default::default(), |
| 73 | + }; |
| 74 | + |
| 75 | + impl_items.push(ImplItem::Type(impl_item_type)); |
| 76 | + } |
| 77 | + TraitItem::Fn(trait_item_fn) => { |
| 78 | + let fn_block = trait_item_fn |
| 79 | + .default |
| 80 | + .as_ref() |
| 81 | + .ok_or_else(|| { |
| 82 | + Error::new_spanned( |
| 83 | + &trait_item_fn, |
| 84 | + "function item require implementation block", |
| 85 | + ) |
| 86 | + })? |
| 87 | + .clone(); |
| 88 | + |
| 89 | + trait_item_fn.default.take(); |
| 90 | + |
| 91 | + let impl_item_fn = ImplItemFn { |
| 92 | + attrs: trait_item_fn.attrs.clone(), |
| 93 | + vis: Visibility::Inherited, |
| 94 | + defaultness: None, |
| 95 | + sig: trait_item_fn.sig.clone(), |
| 96 | + block: fn_block, |
| 97 | + }; |
| 98 | + |
| 99 | + impl_items.push(ImplItem::Fn(impl_item_fn)); |
| 100 | + } |
| 101 | + TraitItem::Const(trait_item_const) => { |
| 102 | + let (eq_token, const_expr) = trait_item_const |
| 103 | + .default |
| 104 | + .as_ref() |
| 105 | + .ok_or_else(|| { |
| 106 | + Error::new_spanned( |
| 107 | + &trait_item_const, |
| 108 | + "const item require implementation expression", |
| 109 | + ) |
| 110 | + })? |
| 111 | + .clone(); |
| 112 | + |
| 113 | + trait_item_const.default.take(); |
| 114 | + |
| 115 | + let impl_item_const = ImplItemConst { |
| 116 | + attrs: trait_item_const.attrs.clone(), |
| 117 | + vis: Visibility::Inherited, |
| 118 | + defaultness: None, |
| 119 | + const_token: trait_item_const.const_token, |
| 120 | + ident: trait_item_const.ident.clone(), |
| 121 | + generics: trait_item_const.generics.clone(), |
| 122 | + colon_token: trait_item_const.colon_token, |
| 123 | + ty: trait_item_const.ty.clone(), |
| 124 | + eq_token, |
| 125 | + expr: const_expr, |
| 126 | + semi_token: trait_item_const.semi_token, |
| 127 | + }; |
| 128 | + |
| 129 | + impl_items.push(ImplItem::Const(impl_item_const)); |
| 130 | + } |
| 131 | + _ => return Err(Error::new_spanned(&trait_item, "unsupported trait item")), |
| 132 | + } |
| 133 | + } |
| 134 | + |
| 135 | + let context_type: Type = parse_internal!(#context_ident); |
| 136 | + |
| 137 | + let mut impl_generics = item_trait.generics.clone(); |
| 138 | + |
| 139 | + impl_generics.params.push(parse_internal!(#context_type)); |
| 140 | + |
| 141 | + for assoc_ident in assoc_idents.iter() { |
| 142 | + impl_generics.params.push(parse_internal!(#assoc_ident)); |
| 143 | + } |
| 144 | + |
| 145 | + let supertraits = item_trait.supertraits.clone(); |
| 146 | + |
| 147 | + let where_clause = impl_generics.make_where_clause(); |
| 148 | + where_clause.predicates.push(parse_internal! { |
| 149 | + #context_type: #supertraits |
| 150 | + }); |
| 151 | + |
| 152 | + where_clause.predicates.extend(assoc_bounds); |
| 153 | + |
| 154 | + let trait_name = &item_trait.ident; |
| 155 | + let (_, type_generics, _) = item_trait.generics.split_for_impl(); |
| 156 | + |
| 157 | + let trait_path: Path = parse_internal! { |
| 158 | + #trait_name #type_generics |
| 159 | + }; |
| 160 | + |
| 161 | + let item_impl = ItemImpl { |
| 162 | + attrs: item_trait.attrs.clone(), |
| 163 | + defaultness: None, |
| 164 | + unsafety: item_trait.unsafety, |
| 165 | + impl_token: Default::default(), |
| 166 | + generics: impl_generics, |
| 167 | + trait_: Some((None, trait_path, Default::default())), |
| 168 | + self_ty: Box::new(context_type), |
| 169 | + brace_token: item_trait.brace_token, |
| 170 | + items: impl_items, |
| 171 | + }; |
| 172 | + |
| 173 | + Ok(item_impl) |
| 174 | + } |
| 175 | +} |
0 commit comments