use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{Result, Token};
const MAX_JUNCTIONS: usize = 8;
pub mod location {
use super::*;
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
}
let from_tuples = generate_conversion_from_tuples(8, 8);
Ok(quote! {
#from_tuples
})
}
fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
let mut from_tuples = (0..=max_junctions)
.map(|num_junctions| {
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
let idents =
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let array_size = num_junctions;
let interior = if num_junctions == 0 {
quote!(Junctions::Here)
} else {
let variant = format_ident!("X{}", num_junctions);
quote! {
Junctions::#variant( alloc::sync::Arc::new( [#(#idents .into()),*] ) )
}
};
let mut from_tuple = quote! {
impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for Location {
fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
Location { parents, interior: #interior }
}
}
impl From<[Junction; #array_size]> for Location {
fn from(j: [Junction; #array_size]) -> Self {
let [#(#idents),*] = j;
Location { parents: 0, interior: #interior }
}
}
};
let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
let parents =
(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
let underscores =
(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
quote! {
impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for Location {
fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
Self { parents: #cur_parents as u8, interior: #interior }
}
}
}
});
from_tuple.extend(from_parent_tuples);
from_tuple
})
.collect::<TokenStream>();
let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
let underscores =
(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
quote! {
impl From<( #(#parents,)* Junctions )> for Location {
fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
Location { parents: #cur_parents as u8, interior: junctions }
}
}
}
});
from_tuples.extend(from_parent_junctions_tuples);
quote! {
impl From<(Ancestor, Junctions)> for Location {
fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
Location { parents, interior }
}
}
impl From<Junction> for Location {
fn from(x: Junction) -> Self {
Location { parents: 0, interior: [x].into() }
}
}
#from_tuples
}
}
}
pub mod junctions {
use super::*;
pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
}
let from_v3 = generate_conversion_from_v3(MAX_JUNCTIONS);
let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
Ok(quote! {
#from_v3
#from_tuples
})
}
fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
(1..=max_junctions)
.map(|num_junctions| {
let idents =
(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
quote! {
impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
[#(#idents .into()),*].into()
}
}
}
})
.collect()
}
fn generate_conversion_from_v3(max_junctions: usize) -> TokenStream {
let match_variants = (0..max_junctions)
.map(|cur_num| {
let num_ancestors = cur_num + 1;
let variant = format_ident!("X{}", num_ancestors);
let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let convert = idents
.iter()
.map(|ident| {
quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
})
.collect::<Vec<_>>();
quote! {
crate::v3::Junctions::#variant( #(#idents),* ) => {
#(#convert);*;
let junctions: Junctions = [#(#idents),*].into();
junctions
},
}
})
.collect::<TokenStream>();
quote! {
impl core::convert::TryFrom<crate::v3::Junctions> for Junctions {
type Error = ();
fn try_from(mut old: crate::v3::Junctions) -> core::result::Result<Self, ()> {
Ok(match old {
crate::v3::Junctions::Here => Junctions::Here,
#match_variants
})
}
}
}
}
}