ferment_sys/ext/abstract/
join.rs

1use 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 {}