xsd_parser/models/code/
ident_path.rs1use std::ops::{Deref, DerefMut};
2use std::str::FromStr;
3
4use proc_macro2::{Ident as Ident2, TokenStream};
5use quote::{format_ident, quote, ToTokens};
6use smallvec::SmallVec;
7use thiserror::Error;
8
9use crate::models::{meta::MetaTypes, schema::NamespaceId};
10
11use super::format_module_ident;
12
13#[derive(Debug, Clone, Eq, PartialEq)]
23pub struct IdentPath {
24 path: Option<ModulePath>,
25 ident: Ident2,
26}
27
28#[derive(Default, Debug, Clone, Eq, PartialEq)]
33pub struct ModulePath(pub SmallVec<[Ident2; 2]>);
34
35#[derive(Debug, Error)]
37#[error("Invalid identifier path: {0}")]
38pub struct InvalidIdentPath(pub String);
39
40impl IdentPath {
41 #[must_use]
44 pub fn from_parts<I>(path: I, ident: Ident2) -> Self
45 where
46 I: IntoIterator<Item = Ident2>,
47 {
48 Self::from_ident(ident).with_path(path)
49 }
50
51 #[must_use]
54 pub fn from_ident(ident: Ident2) -> Self {
55 Self { ident, path: None }
56 }
57
58 #[must_use]
60 pub fn with_ident(mut self, ident: Ident2) -> Self {
61 self.ident = ident;
62
63 self
64 }
65
66 #[must_use]
68 pub fn with_path<I>(mut self, path: I) -> Self
69 where
70 I: IntoIterator<Item = Ident2>,
71 {
72 self.path = Some(ModulePath(path.into_iter().collect()));
73
74 self
75 }
76
77 #[must_use]
80 pub fn into_parts(self) -> (Ident2, Option<ModulePath>) {
81 let Self { ident, path } = self;
82
83 (ident, path)
84 }
85
86 #[must_use]
88 pub fn ident(&self) -> &Ident2 {
89 &self.ident
90 }
91
92 #[must_use]
97 pub fn relative_to(&self, dst: &ModulePath) -> TokenStream {
98 let ident = &self.ident;
99
100 let Some(src) = &self.path else {
101 return quote!(#ident);
102 };
103
104 let mut ret = TokenStream::new();
105 let mut src = src.0.iter().fuse();
106 let mut dst = dst.0.iter().fuse();
107
108 macro_rules! push {
109 ($x:expr) => {{
110 let x = $x;
111 if ret.is_empty() {
112 ret.extend(x)
113 } else {
114 ret.extend(quote!(::#x))
115 }
116 }};
117 }
118
119 loop {
120 match (src.next(), dst.next()) {
121 (Some(a), Some(b)) if a == b => {}
122 (Some(a), Some(_)) => {
123 push!(quote!(super));
124 while dst.next().is_some() {
125 push!(quote!(super));
126 }
127
128 push!(quote!(#a));
129 for a in src {
130 push!(quote!(#a));
131 }
132
133 push!(quote!(#ident));
134
135 return ret;
136 }
137 (Some(a), None) => push!(quote!(#a)),
138 (None, Some(_)) => push!(quote!(super)),
139 (None, None) => {
140 push!(quote!(#ident));
141 return ret;
142 }
143 }
144 }
145 }
146}
147
148impl TryFrom<&str> for IdentPath {
149 type Error = InvalidIdentPath;
150
151 fn try_from(value: &str) -> Result<Self, Self::Error> {
152 Self::from_str(value)
153 }
154}
155
156impl TryFrom<String> for IdentPath {
157 type Error = InvalidIdentPath;
158
159 fn try_from(value: String) -> Result<Self, Self::Error> {
160 Self::from_str(&value)
161 }
162}
163
164impl FromStr for IdentPath {
165 type Err = InvalidIdentPath;
166
167 fn from_str(s: &str) -> Result<Self, Self::Err> {
168 let mut ident = None;
169 let mut path = ModulePath::default();
170
171 for part in s.split("::") {
172 let part = part.trim();
173 if part.is_empty() {
174 continue;
175 }
176
177 if let Some(ident) = ident.take() {
178 path.0.push(ident);
179 }
180
181 ident = Some(format_ident!("{part}"));
182 }
183
184 Ok(Self {
185 ident: ident.ok_or_else(|| InvalidIdentPath(s.into()))?,
186 path: Some(path),
187 })
188 }
189}
190
191impl ToTokens for IdentPath {
192 fn to_tokens(&self, tokens: &mut TokenStream) {
193 if let Some(path) = &self.path {
194 for module in &path.0 {
195 tokens.extend(quote!(#module::));
196 }
197 }
198
199 let ident = self.ident();
200
201 tokens.extend(quote!(#ident));
202 }
203}
204
205impl ModulePath {
206 #[must_use]
212 pub fn from_namespace(ns: Option<NamespaceId>, types: &MetaTypes) -> Self {
213 let ident = ns
214 .and_then(|id| types.modules.get(&id))
215 .and_then(|module| module.name.as_ref())
216 .map(format_module_ident);
217
218 Self(ident.into_iter().collect())
219 }
220
221 #[must_use]
223 pub fn join(mut self, other: Ident2) -> Self {
224 self.0.push(other);
225
226 self
227 }
228}
229
230impl Deref for ModulePath {
231 type Target = SmallVec<[Ident2; 2]>;
232
233 fn deref(&self) -> &Self::Target {
234 &self.0
235 }
236}
237
238impl DerefMut for ModulePath {
239 fn deref_mut(&mut self) -> &mut Self::Target {
240 &mut self.0
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use quote::{format_ident, quote};
247
248 use super::{IdentPath, ModulePath};
249
250 #[test]
251 #[rustfmt::skip]
252 fn type_path() {
253 let string = IdentPath::from_ident(format_ident!("String"));
254 let my_type = IdentPath::from_parts(
255 [format_ident!("my_module")],
256 format_ident!("MyType"),
257 );
258 let serializer = IdentPath::from_parts(
259 [
260 format_ident!("my_module"),
261 format_ident!("quick_xml_serialize"),
262 ],
263 format_ident!("MyTypeSerializer"),
264 );
265 let deserializer = IdentPath::from_parts(
266 [
267 format_ident!("my_module"),
268 format_ident!("quick_xml_deserialize"),
269 ],
270 format_ident!("MyTypeDeserializer"),
271 );
272
273 let empty_path = ModulePath::default();
274 let module_path = ModulePath::default().join(format_ident!("my_module"));
275 let other_module_path = ModulePath::default().join(format_ident!("other_module"));
276 let serializer_path = module_path.clone().join(format_ident!("quick_xml_serialize"));
277 let deserializer_path = module_path.clone().join(format_ident!("quick_xml_deserialize"));
278
279 macro_rules! test {
280 ($actual:expr, $( $expected:tt )*) => {{
281 let a = $actual.to_string();
282 let b = quote!($( $expected )*).to_string();
283
284 assert_eq!(a, b);
285 }};
286 }
287
288 test!(string.relative_to(&empty_path), String);
291 test!(string.relative_to(&module_path), String);
292 test!(string.relative_to(&other_module_path), String);
293 test!(string.relative_to(&serializer_path), String);
294 test!(string.relative_to(&deserializer_path), String);
295
296 test!(my_type.relative_to(&empty_path), my_module::MyType);
297 test!(my_type.relative_to(&module_path), MyType);
298 test!(my_type.relative_to(&other_module_path), super::my_module::MyType);
299 test!(my_type.relative_to(&serializer_path), super::MyType);
300 test!(my_type.relative_to(&deserializer_path), super::MyType);
301
302 test!(serializer.relative_to(&empty_path), my_module::quick_xml_serialize::MyTypeSerializer);
303 test!(serializer.relative_to(&module_path), quick_xml_serialize::MyTypeSerializer);
304 test!(serializer.relative_to(&other_module_path), super::my_module::quick_xml_serialize::MyTypeSerializer);
305 test!(serializer.relative_to(&serializer_path), MyTypeSerializer);
306 test!(serializer.relative_to(&deserializer_path), super::quick_xml_serialize::MyTypeSerializer);
307
308 test!(deserializer.relative_to(&empty_path), my_module::quick_xml_deserialize::MyTypeDeserializer);
309 test!(deserializer.relative_to(&module_path), quick_xml_deserialize::MyTypeDeserializer);
310 test!(deserializer.relative_to(&other_module_path), super::my_module::quick_xml_deserialize::MyTypeDeserializer);
311 test!(deserializer.relative_to(&serializer_path), super::quick_xml_deserialize::MyTypeDeserializer);
312 test!(deserializer.relative_to(&deserializer_path), MyTypeDeserializer);
313 }
314}