1use proc_macro2::{Span, TokenStream};
18use quote::{format_ident, quote};
19use syn::{Result, Token};
20
21const MAX_JUNCTIONS: usize = 8;
22
23pub mod location {
24 use super::*;
25
26 pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
30 if !input.is_empty() {
31 return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
32 }
33
34 let from_tuples = generate_conversion_from_tuples(8, 8);
35
36 Ok(quote! {
37 #from_tuples
38 })
39 }
40
41 fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
42 let mut from_tuples = (0..=max_junctions)
43 .map(|num_junctions| {
44 let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
45 let idents =
46 (0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
47 let array_size = num_junctions;
48 let interior = if num_junctions == 0 {
49 quote!(Junctions::Here)
50 } else {
51 let variant = format_ident!("X{}", num_junctions);
52 quote! {
53 Junctions::#variant( alloc::sync::Arc::new( [#(#idents .into()),*] ) )
54 }
55 };
56
57 let mut from_tuple = quote! {
58 impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for Location {
59 fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
60 Location { parents, interior: #interior }
61 }
62 }
63
64 impl From<[Junction; #array_size]> for Location {
65 fn from(j: [Junction; #array_size]) -> Self {
66 let [#(#idents),*] = j;
67 Location { parents: 0, interior: #interior }
68 }
69 }
70 };
71
72 let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
73 let parents =
74 (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
75 let underscores =
76 (0..cur_parents).map(|_| Token)).collect::<Vec<_>>();
77
78 quote! {
79 impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for Location {
80 fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
81 Self { parents: #cur_parents as u8, interior: #interior }
82 }
83 }
84 }
85 });
86
87 from_tuple.extend(from_parent_tuples);
88 from_tuple
89 })
90 .collect::<TokenStream>();
91
92 let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
93 let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
94 let underscores =
95 (0..cur_parents).map(|_| Token)).collect::<Vec<_>>();
96
97 quote! {
98 impl From<( #(#parents,)* Junctions )> for Location {
99 fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
100 Location { parents: #cur_parents as u8, interior: junctions }
101 }
102 }
103 }
104 });
105 from_tuples.extend(from_parent_junctions_tuples);
106
107 quote! {
108 impl From<(Ancestor, Junctions)> for Location {
109 fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
110 Location { parents, interior }
111 }
112 }
113
114 impl From<Junction> for Location {
115 fn from(x: Junction) -> Self {
116 Location { parents: 0, interior: [x].into() }
117 }
118 }
119
120 #from_tuples
121 }
122 }
123}
124
125pub mod junctions {
126 use super::*;
127
128 pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
129 if !input.is_empty() {
130 return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
131 }
132
133 let from_v3 = generate_conversion_from_v3(MAX_JUNCTIONS);
135 let from_v5 = generate_conversion_from_v5(MAX_JUNCTIONS);
136 let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
137
138 Ok(quote! {
139 #from_v3
140 #from_v5
141 #from_tuples
142 })
143 }
144
145 fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
146 (1..=max_junctions)
147 .map(|num_junctions| {
148 let idents =
149 (0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
150 let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
151
152 quote! {
153 impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
154 fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
155 [#(#idents .into()),*].into()
156 }
157 }
158 }
159 })
160 .collect()
161 }
162
163 fn generate_conversion_from_v3(max_junctions: usize) -> TokenStream {
164 let match_variants = (0..max_junctions)
165 .map(|cur_num| {
166 let num_ancestors = cur_num + 1;
167 let variant = format_ident!("X{}", num_ancestors);
168 let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
169 let convert = idents
170 .iter()
171 .map(|ident| {
172 quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
173 })
174 .collect::<Vec<_>>();
175
176 quote! {
177 crate::v3::Junctions::#variant( #(#idents),* ) => {
178 #(#convert);*;
179 let junctions: Junctions = [#(#idents),*].into();
180 junctions
181 },
182 }
183 })
184 .collect::<TokenStream>();
185
186 quote! {
187 impl core::convert::TryFrom<crate::v3::Junctions> for Junctions {
188 type Error = ();
189 fn try_from(mut old: crate::v3::Junctions) -> core::result::Result<Self, ()> {
190 Ok(match old {
191 crate::v3::Junctions::Here => Junctions::Here,
192 #match_variants
193 })
194 }
195 }
196 }
197 }
198
199 fn generate_conversion_from_v5(max_junctions: usize) -> TokenStream {
200 let match_variants = (0..max_junctions)
201 .map(|current_number| {
202 let number_ancestors = current_number + 1;
203 let variant = format_ident!("X{}", number_ancestors);
204 let idents =
205 (0..=current_number).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
206 let convert = idents
207 .iter()
208 .map(|ident| {
209 quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
210 })
211 .collect::<Vec<_>>();
212
213 quote! {
214 crate::v5::Junctions::#variant( junctions ) => {
215 let [#(#idents),*] = &*junctions;
216 #(#convert);*
217 [#(#idents),*].into()
218 },
219 }
220 })
221 .collect::<TokenStream>();
222
223 quote! {
224 impl core::convert::TryFrom<crate::v5::Junctions> for Junctions {
225 type Error = ();
226
227 fn try_from(mut new: crate::v5::Junctions) -> core::result::Result<Self, Self::Error> {
228 use Junctions::*;
229 Ok(match new {
230 crate::v5::Junctions::Here => Here,
231 #match_variants
232 })
233 }
234 }
235 }
236 }
237}