power_protobuf_lib/
resolve.rs

1use std::collections::HashMap;
2
3use convert_case::{Case, Casing};
4use syn::{punctuated::Punctuated, spanned::Spanned, Ident, PathSegment, TypeTuple};
5use syn_prelude::{JoinSynErrors, ToErr, ToIdent, ToIdentWithCase, ToSynError};
6
7use crate::{
8    dep::Deps,
9    model::{FieldType, Import, Message, MessageElement, Package, Type},
10};
11
12#[derive(Debug)]
13pub struct ResolveContext<'a> {
14    pub package: &'a Option<Package>,
15    pub types: HashMap<Ident, InsideType>,
16    pub deps: &'a Deps,
17    pub imports: &'a Vec<Import>,
18}
19
20#[derive(Debug)]
21pub enum InsideType {
22    Message(MessageHierarchy),
23    Enum(Ident),
24}
25
26#[derive(Debug)]
27pub struct MessageHierarchy {
28    pub name: Vec<Ident>,
29    pub inner_messages: Option<Vec<MessageHierarchy>>,
30    pub inner_enums: Option<Vec<Ident>>,
31}
32
33impl Message {
34    pub fn resolve(&mut self, ctx: &ResolveContext) -> syn::Result<()> {
35        if let Some(InsideType::Message(hierarchy)) = ctx.types.get(&self.name) {
36            self.resolve_field_types(ctx, hierarchy)
37        } else {
38            Ok(())
39        }
40    }
41    fn resolve_field_types(
42        &mut self,
43        ctx: &ResolveContext,
44        hierarchy: &MessageHierarchy,
45    ) -> syn::Result<()> {
46        let result = self
47            .messages
48            .iter_mut()
49            .enumerate()
50            .filter_map(|(index, inner_message)| {
51                hierarchy.inner_messages.as_ref().map(|messages| {
52                    inner_message.resolve_field_types(ctx, messages.get(index).unwrap())
53                })
54            })
55            .collect::<Vec<_>>()
56            .join_errors();
57
58        let result2 = self
59            .fields
60            .iter_mut()
61            .map(|f| match f {
62                MessageElement::Field(f) => ctx.resolve_field_type(Some(hierarchy), &mut f.typ),
63                MessageElement::OneOf(oneof) => oneof
64                    .fields
65                    .iter_mut()
66                    .map(|f| ctx.resolve_field_type(Some(hierarchy), &mut f.typ))
67                    .collect::<Vec<syn::Result<_>>>()
68                    .join_errors(),
69            })
70            .collect::<Vec<syn::Result<_>>>()
71            .join_errors();
72
73        (result, result2).join_errors()
74    }
75}
76
77impl From<(&Vec<Ident>, &Message)> for MessageHierarchy {
78    fn from((path, value): (&Vec<Ident>, &Message)) -> Self {
79        let mut current_path = Vec::with_capacity(path.len() + 1);
80        current_path.clone_from(path);
81        current_path.push(value.name.clone());
82        let inner_messages = if value.messages.is_empty() {
83            None
84        } else {
85            Some(
86                value
87                    .messages
88                    .iter()
89                    .map(|m| Self::from((&current_path, m)))
90                    .collect::<Vec<_>>(),
91            )
92        };
93        let inner_enums = if value.enums.is_empty() {
94            None
95        } else {
96            Some(
97                value
98                    .enums
99                    .iter()
100                    .map(|e| e.name.clone())
101                    .collect::<Vec<_>>(),
102            )
103        };
104        Self {
105            name: current_path,
106            inner_messages,
107            inner_enums,
108        }
109    }
110}
111
112impl MessageHierarchy {
113    fn find_message(&self, name: &Ident) -> Option<&Self> {
114        if let Some(inner_messages) = &self.inner_messages {
115            inner_messages
116                .iter()
117                .find(|m| m.name.last().map(|n| n.eq(name)).unwrap_or_default())
118        } else {
119            None
120        }
121    }
122
123    fn find_enum(&self, name: &Ident) -> Option<&Ident> {
124        if let Some(inner_enums) = &self.inner_enums {
125            inner_enums.iter().find(|e| name.eq(*e))
126        } else {
127            None
128        }
129    }
130}
131
132impl ResolveContext<'_> {
133    pub fn resolve_type(
134        &self,
135        parent: Option<&MessageHierarchy>,
136        typ: &mut Type,
137    ) -> syn::Result<()> {
138        let import0 = self.imports.get(0).unwrap();
139        let type_path_seg_first = typ
140            .type_path
141            .segments
142            .first()
143            .ok_or(typ.type_path.span().to_syn_error("missing type name"))?;
144
145        // lookup inner types
146        if let Some(container) = parent {
147            let mut type_name_iter = typ.type_path.segments.iter();
148            if let Some(is_message) = Self::match_with_message_inner_type(
149                import0,
150                self.package.as_ref().map(|p| &p.package),
151                container,
152                &mut type_name_iter,
153                &mut typ.ty,
154            )? {
155                typ.target_is_message = is_message;
156                return Ok(());
157            }
158        }
159        // search in proto
160        if let Some(t) = self.types.get(type_path_seg_first) {
161            match t {
162                InsideType::Message(hierarchy) => {
163                    if typ.type_path.segments.len() > 1 {
164                        if let Some(is_message) = Self::match_with_message_inner_type(
165                            import0,
166                            self.package.as_ref().map(|p| &p.package),
167                            hierarchy,
168                            &mut typ.type_path.segments.iter().skip(1),
169                            &mut typ.ty,
170                        )? {
171                            typ.target_is_message = is_message;
172                            return Ok(());
173                        }
174                    } else {
175                        typ.ty.push_import_with_scope(
176                            import0,
177                            self.package.as_ref().map(|p| &p.package),
178                        );
179                        typ.ty.push(type_path_seg_first);
180                        typ.target_is_message = true;
181                        return Ok(());
182                    }
183                }
184                InsideType::Enum(e) => {
185                    if typ.type_path.segments.len() > 1 {
186                        typ.type_path
187                            .span()
188                            .to_syn_error("cannot find this type in inner enumeration")
189                            .to_err()?;
190                    } else {
191                        typ.ty.push_import_with_scope(
192                            import0,
193                            self.package.as_ref().map(|p| &p.package),
194                        );
195                        typ.ty.push(e);
196                        typ.target_is_message = false;
197                        return Ok(());
198                    }
199                }
200            }
201        }
202        // search in import-wide
203        let type_path_first_str = type_path_seg_first.to_string();
204        let try_package_name = type_path_seg_first.clone();
205        if if type_path_first_str.is_case(Case::UpperCamel) {
206            // try search default scope first
207            self.match_with_external_type(None, typ)?
208                || self.match_with_external_type(Some(&try_package_name), typ)?
209        } else {
210            self.match_with_external_type(Some(&try_package_name), typ)?
211                || self.match_with_external_type(None, typ)?
212        } {
213            return Ok(());
214        }
215
216        typ.type_path
217            .span()
218            .to_syn_error(&format!(
219                "no such type '{}'",
220                typ.type_path
221                    .segments
222                    .iter()
223                    .map(|s| s.to_string())
224                    .collect::<Vec<_>>()
225                    .join(".")
226            ))
227            .to_err()
228    }
229
230    pub fn resolve_field_type(
231        &self,
232        parent: Option<&MessageHierarchy>,
233        typ: &mut FieldType,
234    ) -> syn::Result<()> {
235        match typ {
236            FieldType::MessageOrEnum(typ) => self.resolve_type(parent, typ),
237            FieldType::Map(map) => (
238                self.resolve_field_type(parent, map.key.as_mut()),
239                self.resolve_field_type(parent, map.value.as_mut()),
240            )
241                .join_errors(),
242            _ => Ok(()),
243        }
244    }
245
246    fn match_with_message_inner_type<'a>(
247        import0: &Import,
248        package: Option<&Ident>,
249        hierarchy: &'a MessageHierarchy,
250        type_name_iter: &mut impl Iterator<Item = &'a Ident>,
251        full_type_path: &mut syn::Type,
252    ) -> syn::Result<Option<bool>> {
253        if let Some(type_name_seg) = type_name_iter.next() {
254            if let Some(msg) = hierarchy.find_message(type_name_seg) {
255                let (left, _) = type_name_iter.size_hint();
256                if left == 0 {
257                    full_type_path.push_import_with_scope(import0, package);
258                    full_type_path.push_type_vec(&msg.name, false);
259                    return Ok(Some(true));
260                }
261                Self::match_with_message_inner_type(
262                    import0,
263                    package,
264                    msg,
265                    type_name_iter,
266                    full_type_path,
267                )
268            } else if let Some(enum_name) = hierarchy.find_enum(type_name_seg) {
269                let (left, _) = type_name_iter.size_hint();
270                if left == 0 {
271                    full_type_path.push_import_with_scope(import0, package);
272                    full_type_path.push_type_vec(&hierarchy.name, true);
273                    full_type_path.push(enum_name);
274                    Ok(Some(false))
275                } else {
276                    // cannot find more types in enumeration
277                    type_name_seg
278                        .to_syn_error("cannot find this type in inner enumeration")
279                        .to_err()
280                }
281            } else {
282                // cannot find this inner type in message
283                Ok(None)
284            }
285        } else {
286            // unreachable
287            Ok(None)
288        }
289    }
290
291    fn match_with_external_type(
292        &self,
293        package: Option<&Ident>,
294        typ: &mut Type,
295    ) -> syn::Result<bool> {
296        let skip = if package.is_some() { 1 } else { 0 };
297        if let Some(scope) = self
298            .deps
299            .scopes
300            .get(&package.map(|p| p.to_string()).unwrap_or_default())
301        {
302            let type_path_str = typ
303                .type_path
304                .segments
305                .iter()
306                .skip(skip)
307                .map(|s| s.to_string())
308                .collect::<Vec<_>>()
309                .join(".");
310            if let Some(x) = scope.get(&type_path_str) {
311                if x.prost_type {
312                    let mut type_name_iter = typ.type_path.segments.iter().skip(2);
313                    if let Some(ty) = type_name_iter.next() {
314                        match ty.to_string().as_str() {
315                            "Empty" => {
316                                typ.ty = syn::Type::Tuple(TypeTuple {
317                                    paren_token: syn::token::Paren(typ.span()),
318                                    elems: Punctuated::new(),
319                                });
320                            }
321                            _ => {
322                                if let Some(inner_type) = type_name_iter.next() {
323                                    typ.ty
324                                        .push_ident(("prost", ty.span()).to_ident())
325                                        .push_ident(ty.to_ident_with_case(Case::Snake))
326                                        .push(inner_type);
327                                } else {
328                                    typ.ty.push_ident(("prost", ty.span()).to_ident()).push(ty);
329                                }
330                            }
331                        }
332                    }
333                } else {
334                    typ.ty = syn::Type::new();
335                    typ.ty
336                        .push_import_with_scope(self.imports.get(x.import_index).unwrap(), package)
337                        .push_type_path(&mut typ.type_path.segments.iter().skip(skip), false);
338                }
339                return Ok(true);
340            }
341        }
342        Ok(false)
343    }
344}
345
346pub trait PathMod {
347    fn new() -> Self;
348    fn from_idents(idents: impl Iterator<Item = Ident>) -> Self;
349    fn push(&mut self, type_name_seg: &Ident) -> &mut Self;
350    fn push_ident(&mut self, type_name_seg: Ident) -> &mut Self;
351    fn push_import_with_scope(&mut self, import: &Import, package: Option<&Ident>) -> &mut Self;
352    fn push_type_path<'a>(
353        &mut self,
354        iter: &mut impl Iterator<Item = &'a Ident>,
355        tailing: bool,
356    ) -> &mut Self;
357    fn push_type_vec(&mut self, name: &Vec<Ident>, tailing: bool) -> &mut Self;
358}
359
360impl PathMod for syn::Type {
361    fn new() -> Self {
362        syn::Type::Path(syn::TypePath {
363            qself: None,
364            path: syn::Path::new(),
365        })
366    }
367
368    fn from_idents(idents: impl Iterator<Item = Ident>) -> Self {
369        syn::Type::Path(syn::TypePath {
370            qself: None,
371            path: syn::Path::from_idents(idents),
372        })
373    }
374
375    fn push(&mut self, type_name_seg: &Ident) -> &mut Self {
376        if let syn::Type::Path(type_path) = self {
377            type_path.path.push(type_name_seg);
378        }
379        self
380    }
381
382    fn push_ident(&mut self, type_name_seg: Ident) -> &mut Self {
383        if let syn::Type::Path(type_path) = self {
384            type_path.path.push_ident(type_name_seg);
385        }
386        self
387    }
388
389    fn push_import_with_scope(&mut self, import: &Import, package: Option<&Ident>) -> &mut Self {
390        if let syn::Type::Path(type_path) = self {
391            type_path.path.push_import_with_scope(import, package);
392        }
393        self
394    }
395
396    fn push_type_path<'a>(
397        &mut self,
398        iter: &mut impl Iterator<Item = &'a Ident>,
399        tailing: bool,
400    ) -> &mut Self {
401        if let syn::Type::Path(type_path) = self {
402            type_path.path.push_type_path(iter, tailing);
403        }
404        self
405    }
406
407    fn push_type_vec(&mut self, name: &Vec<Ident>, tailing: bool) -> &mut Self {
408        if let syn::Type::Path(type_path) = self {
409            type_path.path.push_type_vec(name, tailing);
410        }
411        self
412    }
413}
414
415impl PathMod for syn::Path {
416    fn new() -> Self {
417        Self {
418            leading_colon: None,
419            segments: Punctuated::new(),
420        }
421    }
422
423    fn from_idents(mut idents: impl Iterator<Item = Ident>) -> Self {
424        let mut new = Self::new();
425        while let Some(seg) = idents.next() {
426            if new.segments.is_empty() {
427                new.push_ident(("crate", seg.span()).to_ident());
428            }
429            new.push_ident(seg);
430        }
431        new
432    }
433
434    fn push_ident(&mut self, type_name_seg: Ident) -> &mut Self {
435        self.segments.push(PathSegment {
436            ident: type_name_seg,
437            arguments: syn::PathArguments::None,
438        });
439        self
440    }
441
442    fn push(&mut self, type_name_seg: &Ident) -> &mut Self {
443        self.segments.push(PathSegment {
444            ident: type_name_seg.clone(),
445            arguments: syn::PathArguments::None,
446        });
447        self
448    }
449
450    fn push_import_with_scope(&mut self, import: &Import, package: Option<&Ident>) -> &mut Self {
451        if let Some(file_path) = &import.file_path {
452            for seg in file_path.mod_path.segments.iter() {
453                self.segments.push(seg.clone());
454            }
455        }
456        if let Some(package) = package {
457            self.push(package);
458        }
459        self
460    }
461
462    fn push_type_path<'a>(
463        &mut self,
464        iter: &mut impl Iterator<Item = &'a Ident>,
465        tailing: bool,
466    ) -> &mut Self {
467        while let Some(seg) = iter.next() {
468            let (left, _) = iter.size_hint();
469            if tailing || left > 0 {
470                self.push(&seg.to_ident_with_case(Case::Snake));
471            } else {
472                self.push(seg);
473            }
474        }
475        self
476    }
477    fn push_type_vec(&mut self, name: &Vec<Ident>, tailing: bool) -> &mut Self {
478        self.push_type_path(&mut name.iter(), tailing)
479    }
480}