Skip to content

Commit d4f3639

Browse files
authored
Refactor and move #[blanket_trait] implementation to cgp-macro-core (#238)
* Re-implement `remove_self_path` using visitor * Move blanket trait impl to cgp-macro-core * Remove self path on the whole item trait directly * Use parse_internal * Slight refactoring * Use snapshot testing for blanket_trait
1 parent 5cda4a9 commit d4f3639

14 files changed

Lines changed: 327 additions & 273 deletions

File tree

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
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+
}

crates/macros/cgp-macro-core/src/types/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod attributes;
2+
pub mod blanket_trait;
23
pub mod cgp_auto_getter;
34
pub mod cgp_component;
45
pub mod cgp_fn;

crates/macros/cgp-macro-core/src/visitors/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
mod remove_self_path;
12
mod replace_provider;
23
mod replace_self;
34
mod self_assoc_type;
45
mod substitute_abstract_type;
56

7+
pub use remove_self_path::*;
68
pub use replace_provider::*;
79
pub use replace_self::*;
810
pub use self_assoc_type::*;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use syn::visit_mut::{VisitMut, visit_type_mut};
2+
use syn::{Ident, PathArguments, Type, TypePath};
3+
4+
pub struct RemoveSelfPathVisitor<'a> {
5+
pub assoc_idents: &'a [Ident],
6+
}
7+
8+
impl VisitMut for RemoveSelfPathVisitor<'_> {
9+
fn visit_type_mut(&mut self, node: &mut Type) {
10+
if let Type::Path(TypePath { qself: None, path }) = node
11+
&& path.leading_colon.is_none()
12+
&& path.segments.len() >= 2
13+
&& path.segments[0].ident == "Self"
14+
&& matches!(path.segments[0].arguments, PathArguments::None)
15+
&& self.assoc_idents.contains(&path.segments[1].ident)
16+
{
17+
let segments = std::mem::take(&mut path.segments);
18+
path.segments = segments.into_iter().skip(1).collect();
19+
}
20+
21+
visit_type_mut(self, node);
22+
}
23+
}

crates/macros/cgp-macro-lib/src/blanket_trait/derive.rs

Lines changed: 0 additions & 177 deletions
This file was deleted.

0 commit comments

Comments
 (0)