syn_prelude/
path_helpers.rs1use proc_macro2::Span;
2use syn::{
3 punctuated::Punctuated, spanned::Spanned, Ident, PathArguments, PathSegment, Token, TypePath,
4};
5use syn_prelude_macros::gen_tuples_for_impl_into_idents;
6
7pub trait PathHelpers {
8 fn new() -> Self;
9 fn to_type(self) -> syn::Type;
10 fn from_ident<I: IntoIdent>(origin: I) -> Self;
11 fn from_idents<I: IntoIdents>(origin: I) -> Self;
12 fn push_segment<S: IntoSegment>(&mut self, segment: S) -> &mut Self;
13 fn modify_segment_at<F: FnOnce(&mut PathSegment)>(
14 &mut self,
15 index: usize,
16 modify: F,
17 ) -> &mut Self;
18 fn push_arg(&mut self, index: usize, typ: syn::Type) -> &mut Self {
19 self.modify_segment_at(index, |segment| {
20 let span = typ.span();
21 let arg = syn::GenericArgument::Type(typ);
22 if let syn::PathArguments::AngleBracketed(args) = &mut segment.arguments {
23 args.args.push(arg)
24 } else {
25 segment.arguments =
26 syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
27 colon2_token: None,
28 lt_token: Token,
29 args: {
30 let mut args = Punctuated::new();
31 args.push(arg);
32 args
33 },
34 gt_token: Token,
35 })
36 }
37 })
38 }
39 fn push_ident_arg(&mut self, index: usize, ident: Ident) -> &mut Self {
40 self.push_arg(
41 index,
42 syn::Type::Path(syn::TypePath {
43 qself: None,
44 path: syn::Path::from_ident(ident),
45 }),
46 )
47 }
48}
49
50pub trait IntoSegment {
51 fn into_segment(self) -> PathSegment;
52}
53
54impl IntoSegment for PathSegment {
55 fn into_segment(self) -> PathSegment {
56 self
57 }
58}
59
60impl IntoSegment for &PathSegment {
61 fn into_segment(self) -> PathSegment {
62 self.clone()
63 }
64}
65
66impl IntoSegment for &Ident {
67 fn into_segment(self) -> PathSegment {
68 PathSegment {
69 ident: self.clone(),
70 arguments: PathArguments::None,
71 }
72 }
73}
74
75impl IntoSegment for Ident {
76 fn into_segment(self) -> PathSegment {
77 PathSegment {
78 ident: self,
79 arguments: PathArguments::None,
80 }
81 }
82}
83
84impl IntoSegment for (&str, Span) {
85 fn into_segment(self) -> PathSegment {
86 PathSegment {
87 ident: Ident::new(self.0, self.1),
88 arguments: PathArguments::None,
89 }
90 }
91}
92
93pub trait IntoIdent {
94 fn into_ident(self) -> syn::Ident;
95}
96
97impl IntoIdent for Ident {
98 fn into_ident(self) -> syn::Ident {
99 self
100 }
101}
102
103impl IntoIdent for &Ident {
104 fn into_ident(self) -> syn::Ident {
105 self.clone()
106 }
107}
108
109impl IntoIdent for (&str, Span) {
110 fn into_ident(self) -> syn::Ident {
111 syn::Ident::new(self.0, self.1)
112 }
113}
114
115pub trait IntoIdents {
116 fn into_idents(self) -> impl Iterator<Item = Ident>;
117}
118
119gen_tuples_for_impl_into_idents!(2..=10);
120
121impl PathHelpers for syn::Path {
122 fn new() -> Self {
123 Self {
124 leading_colon: None,
125 segments: Punctuated::new(),
126 }
127 }
128
129 fn to_type(self) -> syn::Type {
130 syn::Type::Path(TypePath {
131 qself: None,
132 path: self,
133 })
134 }
135
136 fn from_ident<I: IntoIdent>(origin: I) -> Self {
137 let mut path = Self::new();
138 path.push_segment(origin.into_ident());
139 path
140 }
141
142 fn from_idents<I: IntoIdents>(origin: I) -> Self {
143 let mut path = Self::new();
144 for ident in origin.into_idents() {
145 path.push_segment(ident);
146 }
147 path
148 }
149
150 fn push_segment<S: IntoSegment>(&mut self, segment: S) -> &mut Self {
151 self.segments.push(segment.into_segment());
152 self
153 }
154
155 fn modify_segment_at<F: FnOnce(&mut PathSegment)>(
156 &mut self,
157 index: usize,
158 modify: F,
159 ) -> &mut Self {
160 if let Some((_, segment)) = self
161 .segments
162 .iter_mut()
163 .enumerate()
164 .find(|(i, _)| *i == index)
165 {
166 modify(segment);
167 }
168 self
169 }
170}