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((¤t_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 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 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 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 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 type_name_seg
278 .to_syn_error("cannot find this type in inner enumeration")
279 .to_err()
280 }
281 } else {
282 Ok(None)
284 }
285 } else {
286 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}