use proc_macro2::TokenStream;
use quote::ToTokens as _;
use syn::{DeriveInput, Ident, Path};
struct Edge
{
parent: TokenStream,
into_parent: Path,
}
pub fn derive_into_ancestors(input: &DeriveInput) -> TokenStream
{
let type_name = &input.ident;
let mut edges: Vec<Edge> = Vec::new();
for attr in &input.attrs {
if !attr.path().is_ident("ancestors") {
continue;
}
let result = attr.parse_nested_meta(|meta| {
let parent = meta.path.segments[0].to_token_stream();
edges.push(Edge {
parent,
into_parent: meta.path,
});
Ok(())
});
if let Err(e) = result {
return e.to_compile_error();
}
}
let mut expanded = TokenStream::new();
for edge in edges {
expanded.extend(generate_impl_for_edge(type_name, edge));
}
expanded
}
fn generate_impl_for_edge(type_name: &Ident, edge: Edge) -> TokenStream
{
let ancestor = edge.parent;
let conversion = edge.into_parent;
quote::quote! {
impl ::core::convert::From<#type_name> for #ancestor {
fn from(child: #type_name) -> #ancestor {
#conversion(::core::convert::Into::into(child))
}
}
}
}