bevy_reflect_derive/
type_path.rs1use proc_macro2::Ident;
2use syn::{
3 parenthesized,
4 parse::{Parse, ParseStream},
5 token::Paren,
6 Generics, Path, PathSegment, Token,
7};
8
9pub(crate) fn parse_path_no_leading_colon(input: ParseStream) -> syn::Result<Path> {
10 if input.peek(Token![::]) {
11 return Err(input.error("did not expect a leading double colon (`::`)"));
12 }
13
14 let path = Path::parse_mod_style(input)?;
15
16 if path.segments.is_empty() {
17 Err(input.error("expected a path"))
18 } else {
19 Ok(path)
20 }
21}
22
23pub(crate) struct CustomPathDef {
27 path: Path,
28 name: Option<Ident>,
29}
30
31impl CustomPathDef {
32 pub fn into_path(mut self, default_name: &Ident) -> Path {
33 let name = PathSegment::from(self.name.unwrap_or_else(|| default_name.clone()));
34 self.path.segments.push(name);
35 self.path
36 }
37
38 pub fn parse_parenthesized(input: ParseStream) -> syn::Result<Option<Self>> {
39 if input.peek(Paren) {
40 let path;
41 parenthesized!(path in input);
42 Ok(Some(path.call(Self::parse)?))
43 } else {
44 Ok(None)
45 }
46 }
47
48 fn parse(input: ParseStream) -> syn::Result<Self> {
49 input.parse::<Token![in]>()?;
50
51 let custom_path = parse_path_no_leading_colon(input)?;
52
53 if !input.peek(Token![as]) {
54 return Ok(Self {
55 path: custom_path,
56 name: None,
57 });
58 }
59
60 input.parse::<Token![as]>()?;
61 let custom_name: Ident = input.parse()?;
62
63 Ok(Self {
64 path: custom_path,
65 name: Some(custom_name),
66 })
67 }
68}
69
70pub(crate) enum NamedTypePathDef {
71 External {
72 path: Path,
73 generics: Generics,
74 custom_path: Option<CustomPathDef>,
75 },
76 Primitive(Ident),
77}
78
79impl Parse for NamedTypePathDef {
80 fn parse(input: ParseStream) -> syn::Result<Self> {
81 let custom_path = CustomPathDef::parse_parenthesized(input)?;
82
83 let path = Path::parse_mod_style(input)?;
84 let mut generics = input.parse::<Generics>()?;
85 generics.where_clause = input.parse()?;
86
87 if path.leading_colon.is_none() && custom_path.is_none() {
88 if path.segments.len() == 1 {
89 let ident = path.segments.into_iter().next().unwrap().ident;
90 Ok(NamedTypePathDef::Primitive(ident))
91 } else {
92 Err(input.error("non-customized paths must start with a double colon (`::`)"))
93 }
94 } else {
95 Ok(NamedTypePathDef::External {
96 path,
97 generics,
98 custom_path,
99 })
100 }
101 }
102}