ferment_sys/ext/abstract/
join.rs1use proc_macro2::Ident;
2use quote::ToTokens;
3use syn::{parse_quote, ImplItemFn, Item, Path, PathSegment, Signature, TraitItemFn, Type, TypePath};
4use syn::punctuated::Punctuated;
5use crate::ast::Colon2Punctuated;
6use crate::composable::TypeModel;
7use crate::context::{Scope, ScopeChain, ScopeContext, ScopeInfo};
8use crate::kind::{ObjectKind, ScopeItemKind};
9use crate::ext::{GenericBoundKey, MaybeAttrs, ToType};
10
11pub trait Join<T: ToTokens> {
12 fn joined(&self, other: &T) -> Self;
13}
14#[macro_export]
15macro_rules! impl_parseable_join {
16 ($SelfTy:ty, $JoinTy:ty) => {
17 impl Join<$JoinTy> for $SelfTy {
18 fn joined(&self, other: &$JoinTy) -> Self {
19 parse_quote!(#self::#other)
20 }
21 }
22 };
23}
24impl_parseable_join!(Path, Path);
25impl_parseable_join!(Path, Type);
26impl_parseable_join!(Type, Path);
27impl_parseable_join!(Type, Colon2Punctuated<PathSegment>);
28impl_parseable_join!(Path, Colon2Punctuated<PathSegment>);
29impl_parseable_join!(Colon2Punctuated<PathSegment>, Colon2Punctuated<PathSegment>);
30impl_parseable_join!(Colon2Punctuated<PathSegment>, Ident);
31impl_parseable_join!(Colon2Punctuated<PathSegment>, Path);
32impl_parseable_join!(TypePath, Colon2Punctuated<PathSegment>);
33impl_parseable_join!(TypePath, Ident);
34
35impl Join<Item> for ScopeChain {
36 fn joined(&self, item: &Item) -> Self {
37 let attrs = item.maybe_attrs().cloned().unwrap_or_default();
38 let self_scope = self.self_scope_ref().joined(item);
39 match item {
40 Item::Const(..) |
41 Item::Type(..) |
42 Item::Enum(..) |
43 Item::Struct(..) =>
44 ScopeChain::object(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
45 Item::Trait(..) =>
46 ScopeChain::r#trait(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
47 Item::Fn(..) =>
48 ScopeChain::r#fn(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
49 Item::Impl(..) =>
50 ScopeChain::r#impl(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
51 Item::Mod(..) =>
52 ScopeChain::r#mod(ScopeInfo::new(attrs, self.crate_ident(), self_scope), self.clone()),
53 _ => self.clone()
54 }
55 }
56}
57impl Join<ImplItemFn> for ScopeChain {
58 fn joined(&self, item: &ImplItemFn) -> Self {
59 let ImplItemFn { attrs, sig, .. } = item;
60 let Signature { ident, generics, .. } = sig;
61 let self_path = self.self_path_ref();
62 let fn_self_scope = self_path.joined(ident);
63 let self_type = fn_self_scope.to_type();
64 ScopeChain::func(
65 Scope::new(fn_self_scope, ObjectKind::new_fn_item(TypeModel::new_generic_non_nested(self_type, generics), ScopeItemKind::fn_ref(sig, self_path))),
66 attrs,
67 self.crate_ident_ref(),
68 self
69 )
70 }
71}
72impl Join<TraitItemFn> for ScopeChain {
73 fn joined(&self, item: &TraitItemFn) -> Self {
74 let TraitItemFn { attrs, sig, .. } = item;
75 let Signature { ident, generics, .. } = sig;
76 let self_path = self.self_path_ref();
77 let fn_self_scope = self_path.joined(ident);
78 let self_type = fn_self_scope.to_type();
79 ScopeChain::func(
80 Scope::new(fn_self_scope, ObjectKind::new_fn_item(TypeModel::new_generic_non_nested(self_type, generics), ScopeItemKind::fn_ref(sig, self_path))),
81 attrs,
82 self.crate_ident_ref(),
83 self
84 )
85 }
86}
87
88impl Join<ImplItemFn> for ScopeContext {
89 fn joined(&self, other: &ImplItemFn) -> Self {
90 Self::with(self.scope.joined(other), self.context.clone())
91 }
92}
93
94impl Join<TraitItemFn> for ScopeContext {
95 fn joined(&self, other: &TraitItemFn) -> Self {
96 Self::with(self.scope.joined(other), self.context.clone())
97 }
98}
99
100impl Join<Ident> for Path {
101 fn joined(&self, other: &Ident) -> Self {
102 let mut new_path = self.clone();
103 new_path.segments.push(PathSegment::from(other.clone()));
104 new_path
105 }
106}
107
108impl Join<GenericBoundKey> for Path {
109 fn joined(&self, other: &GenericBoundKey) -> Self {
110 match other {
111 GenericBoundKey::Ident(ident) => self.joined(ident),
112 GenericBoundKey::Path(path) => self.joined(path)
113 }
114 }
115}
116
117
118pub trait PunctuateOne<T: Default> {
119 fn punctuate_one(self) -> Punctuated<Self, T> where Self: Sized {
120 Punctuated::from_iter([self])
121 }
122}
123
124impl<T, P: ToTokens + Default> PunctuateOne<P> for T {}