1use std::collections::HashMap;
2
3use quote::{TokenStreamExt as _, format_ident, quote};
4use syn::{parse_quote, spanned::Spanned as _};
5
6use crate::{Alias, Options, alias, syn_util, visitor};
7
8#[derive(Debug)]
9pub(crate) struct Root {
10 telety_path: Option<syn::Path>,
11 map_path: syn::Path,
12 generics: syn::Generics,
13 alias_traits: Option<bool>,
14}
15
16#[derive(Debug)]
17enum OwnedOrRef<'l, T> {
18 Owned(T),
19 Ref(&'l T),
20}
21
22impl<'l, T> AsRef<T> for OwnedOrRef<'l, T> {
23 fn as_ref(&self) -> &T {
24 match self {
25 OwnedOrRef::Owned(owned) => owned,
26 OwnedOrRef::Ref(rf) => rf,
27 }
28 }
29}
30
31#[derive(Debug)]
32pub struct Map<'p> {
33 root: OwnedOrRef<'p, Root>,
34 parent: Option<&'p Map<'p>>,
35
36 module: alias::Module,
37 unique_ident: syn::Ident,
38 primary: Option<(alias::Path, alias::Arguments)>,
39 lookup: HashMap<alias::Path, (usize, alias::Arguments, alias::Kind)>,
41 }
44
45impl<'p> Map<'p> {
46 pub(crate) fn new_root(
47 telety_path: Option<syn::Path>,
48 map_path: syn::Path,
49 module: alias::Module,
50 generics: syn::Generics,
51 unique_ident: syn::Ident,
52 options: &Options,
53 ) -> Self {
54 let root = Root {
55 telety_path,
56 map_path,
57 generics,
58 alias_traits: options.alias_traits,
59 };
60
61 Self {
62 root: OwnedOrRef::Owned(root),
63 parent: None,
64
65 module,
66 unique_ident,
67 primary: None,
68 lookup: HashMap::new(),
69 }
71 }
72
73 pub(crate) fn new_child(&'p self, suffix: &str) -> Self {
74 let module = self.module.new_child(suffix);
75 let parent_ident = &self.unique_ident;
76 let unique_ident = format_ident!("{parent_ident}__{suffix}");
77 Self {
78 root: OwnedOrRef::Ref(self.root()),
79 parent: Some(self),
80
81 module,
82 unique_ident,
83 primary: None,
84 lookup: HashMap::new(),
85 }
87 }
88
89 pub(crate) fn set_self(&mut self, self_type: &syn::Path) -> Result<(), alias::Error> {
90 let (path, args) = alias::Path::new(self_type)?;
91 self.primary = Some((path, args));
94
95 Ok(())
96 }
97
98 pub(crate) fn full_lookup<'map>(
99 &'map self,
100 ty: &syn::Path,
101 ) -> Result<Option<Alias<'map>>, alias::Error> {
102 match self.local_lookup(ty)? {
103 some @ Some(_) => Ok(some),
104 None => {
105 if let Some(parent) = self.parent {
106 parent.full_lookup(ty)
107 } else {
108 Ok(None)
109 }
110 }
111 }
112 }
113
114 pub(crate) fn local_lookup<'map>(
115 &'map self,
116 ty: &syn::Path,
117 ) -> Result<Option<Alias<'map>>, alias::Error> {
118 let (path, args) = alias::Path::new(ty)?;
119 if let Some((path, (index, _canon_args, kind))) = self.lookup.get_key_value(&path) {
120 Ok(Some(Alias::new(
121 self,
122 path,
123 alias::Index::Secondary(*index),
124 args,
125 *kind,
126 )))
127 } else {
128 Ok(None)
129 }
130 }
131
132 pub(crate) fn local_get_self(&self) -> Option<Alias<'_>> {
133 if let Some((path, args)) = &self.primary {
134 Some(Alias::new(
135 self,
136 path,
137 alias::Index::Primary,
138 args.clone(),
139 alias::Kind::Type,
140 ))
141 } else {
142 None
143 }
144 }
145
146 fn root(&self) -> &Root {
147 self.root.as_ref()
148 }
149
150 pub fn iter_aliases(&self) -> impl Iterator<Item = Alias<'_>> {
152 let primary_aliases = self.local_get_self().into_iter();
153
154 let secondary_aliases = self.lookup.iter().map(|(path, (index, args, alias_type))| {
155 Alias::new(
156 self,
157 path,
158 alias::Index::Secondary(*index),
159 args.clone(),
160 *alias_type,
161 )
162 });
163
164 primary_aliases.chain(secondary_aliases)
165 }
166}
167
168impl<'p> Map<'p> {
169 pub fn new_sub_map(&self, suffix: &str) -> Map<'_> {
170 Map::new_child(self, suffix)
171 }
172
173 pub fn telety_path(&self) -> Option<&syn::Path> {
174 self.root().telety_path.as_ref()
175 }
176
177 pub fn map_path(&self) -> &syn::Path {
178 &self.root().map_path
179 }
180
181 pub fn module(&self) -> &alias::Module {
182 &self.module
183 }
184
185 pub fn visibility(&self) -> &syn::Visibility {
186 self.module.visibility()
187 }
188
189 pub fn unique_ident(&self) -> &syn::Ident {
190 &self.unique_ident
191 }
192
193 pub fn generics(&self) -> &syn::Generics {
194 &self.root().generics
195 }
196
197 pub fn insert_type(&mut self, ty: &syn::TypePath) -> Result<bool, alias::Error> {
201 if ty.qself.is_some() {
203 return Err(alias::Error::new(
204 ty.span(),
205 alias::error::Kind::AssociatedType,
206 ));
207 }
208 self.insert(&ty.path, alias::Kind::Type)
209 }
210
211 pub fn insert_trait(&mut self, ty: &syn::Path) -> Result<bool, alias::Error> {
215 let can_insert = self
216 .root()
217 .alias_traits
218 .unwrap_or_else(|| ty.leading_colon.is_some() || ty.segments.len() > 1);
219
220 if can_insert {
221 self.insert(ty, alias::Kind::Trait)
222 } else {
223 Err(alias::Error::new(ty.span(), alias::error::Kind::Trait))
224 }
225 }
226
227 fn insert(&mut self, ty: &syn::Path, alias_type: alias::Kind) -> Result<bool, alias::Error> {
228 if ty.is_ident("Self") {
229 Ok(false)
231 } else if self.full_lookup(ty)?.is_some() {
232 Ok(false)
234 } else {
235 let (path, mut args) = alias::Path::new(ty)?;
236
237 let index = self.lookup.len();
238 args.parameterize();
239
240 self.lookup.insert(path, (index, args, alias_type));
241
242 Ok(true)
243 }
244 }
245
246 pub fn get_self(&self) -> Option<Alias<'_>> {
247 if let Some(alias) = self.local_get_self() {
248 Some(alias)
249 } else if let Some(parent) = self.parent {
250 parent.get_self()
251 } else {
252 None
253 }
254 }
255
256 pub fn get_alias<'map>(
257 &'map self,
258 ty: &syn::Path,
259 ) -> Result<Option<Alias<'map>>, alias::Error> {
260 if ty == &parse_quote!(Self) {
261 Ok(self.get_self())
262 } else {
263 self.full_lookup(ty)
264 }
265 }
266
267 pub fn visitor(&self) -> visitor::ApplyAliases<'_> {
268 visitor::ApplyAliases::new(self)
269 }
270
271 pub fn with_module(&self) -> impl quote::ToTokens + use<'_> {
272 self.module.with_contents(self)
273 }
274}
275
276impl<'p> quote::ToTokens for Map<'p> {
277 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
278 let super_visibility = syn_util::super_visibility(self.module.visibility());
280
281 let exact_aliases = self.iter_aliases().map(alias::Alias::exact);
282
283 let public_aliases = self.iter_aliases().map(alias::Alias::public);
284
285 let map_mod = quote! {
286 mod exact {
287 #super_visibility use super::super::*;
288
289 #(#exact_aliases)*
290 }
291
292 #(#public_aliases)*
293 };
294
295 tokens.append_all(map_mod);
296 }
297}