1use quote::format_ident;
2use syn::{
3 AngleBracketedGenericArguments, Attribute, GenericArgument, Ident, Item, Path, PathArguments,
4 PathSegment, Visibility, spanned::Spanned,
5};
6
7use crate::{
8 Options, alias,
9 item_data::{ItemData as _, Namespaces},
10 syn_util, visitor,
11};
12
13pub struct Telety<'item> {
16 options: Options,
17 item: &'item Item,
18 alias_map: alias::Map<'static>,
19 macro_ident: Ident,
20 visibility: Visibility,
21}
22
23impl<'item> Telety<'item> {
24 #[doc(hidden)]
25 pub fn new_with_options(item: &'item Item, options: Options) -> syn::Result<Self> {
26 if let Some(ident) = item.ident()
27 && ident.namespaces.contains(Namespaces::Macro)
28 {
29 return Err(syn::Error::new(
30 item.span(),
31 "Cannot be applied to items in the macro namespace",
32 ));
33 }
34
35 let Some(macro_ident) = options
36 .macro_ident
37 .as_ref()
38 .or(item.ident().map(|i| i.ident))
39 .cloned()
40 else {
41 return Err(syn::Error::new(
42 item.span(),
43 "Items without an identifier require a 'macro_ident' argument",
44 ));
45 };
46
47 let Some(visibility) = options.visibility.as_ref().or(item.vis()).cloned() else {
48 return Err(syn::Error::new(
49 item.span(),
50 "Items without a visibility require a 'visibility' argument",
51 ));
52 };
53
54 let unique_ident = Self::make_unique_ident(&options, ¯o_ident);
55
56 let parameters = item.generics().cloned().unwrap_or_default();
57
58 let self_type = {
59 let arguments = PathArguments::AngleBracketed(AngleBracketedGenericArguments {
60 colon2_token: None,
61 lt_token: Default::default(),
62 args: syn_util::generic_params_to_arguments(¶meters),
63 gt_token: Default::default(),
64 });
65 let mut path = options.converted_containing_path();
67 path.segments.push(PathSegment {
68 ident: item.ident().unwrap().ident.clone(),
69 arguments,
70 });
71
72 path
73 };
74
75 let module = alias::Module::from_named_item(item)?;
76
77 let mut alias_map = alias::Map::new_root(
78 options.telety_path.clone(),
79 options.converted_containing_path(),
80 module,
81 parameters.clone(),
82 unique_ident,
83 &options,
84 );
85 alias_map.set_self(&self_type)?;
86
87 let mut identify_visitor = visitor::identify_aliases::IdentifyAliases::new(&mut alias_map);
90 directed_visit::visit(
91 &mut directed_visit::syn::direct::FullDefault,
92 &mut identify_visitor,
93 item,
94 );
95
96 Ok(Self {
97 options,
98 item,
99 alias_map,
100 macro_ident,
101 visibility,
102 })
103 }
104
105 pub fn new(item: &'item Item) -> syn::Result<Self> {
109 let options = Options::from_attrs(item.attrs())?;
110
111 Self::new_with_options(item, options)
112 }
113
114 pub fn options(&self) -> &Options {
115 &self.options
116 }
117
118 pub fn alias_map(&self) -> &alias::Map<'_> {
121 &self.alias_map
122 }
123
124 #[doc(hidden)]
125 pub fn visibility(&self) -> &Visibility {
126 &self.visibility
127 }
128
129 pub fn generics_visitor<'a>(
141 &self,
142 generic_arguments: impl IntoIterator<Item = &'a GenericArgument>,
143 ) -> syn::Result<visitor::ApplyGenericArguments<'_>> {
144 let Some(parameters) = self.item.generics() else {
145 return Err(syn::Error::new(
146 self.item.span(),
147 "Item kind does not have generic parameters",
148 ));
149 };
150
151 visitor::ApplyGenericArguments::new(parameters, generic_arguments)
152 }
153
154 pub fn item(&self) -> &Item {
156 self.item
157 }
158
159 pub fn path(&self) -> Path {
162 let mut path = self.options.module_path.clone();
163 if let Some(ident) = self.item.ident() {
164 path.segments.push(PathSegment {
165 ident: ident.ident.clone(),
166 arguments: PathArguments::None,
167 });
168 }
169 path
170 }
171
172 pub fn attributes(&self) -> &[Attribute] {
174 self.item.attrs()
175 }
176
177 pub fn containing_mod_path(&self) -> Path {
180 self.options.converted_containing_path()
181 }
182
183 pub fn macro_ident(&self) -> &Ident {
184 &self.macro_ident
185 }
186
187 fn module_path_ident(options: &Options) -> Ident {
188 let mut iter = options.module_path.segments.iter();
189 let mut unique_ident = iter
190 .next()
191 .expect("Path must have at least one segment")
192 .ident
193 .clone();
194 for segment in iter {
195 let i = &segment.ident;
196 unique_ident = format_ident!("{unique_ident}_{i}");
197 }
198 unique_ident
199 }
200
201 fn make_unique_ident(options: &Options, suffix: &Ident) -> Ident {
202 let module_path_ident = Self::module_path_ident(options);
203 format_ident!("{module_path_ident}_{suffix}")
204 }
205}