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