use darling::{ast, FromDeriveInput, FromField};
use proc_macro2::{Ident, TokenStream};
use std::collections::HashMap;
use quote::{format_ident, quote, quote_spanned};
use syn::spanned::Spanned;
use syn::Expr;
use syn::{parse_macro_input, parse_quote, Fields, GenericParam, Generics};
use syn::{Data, DeriveInput};
#[derive(FromDeriveInput, Debug)]
#[darling(attributes(oxyroot))]
struct GOpts {
branch_prefix: Option<String>,
slicable: Option<bool>,
data: ast::Data<(), FOpts>,
}
#[derive(FromField, Default, Debug)]
#[darling(default, attributes(oxyroot))]
struct FOpts {
rename: Option<String>,
branch_prefix: Option<String>,
absolute_name: Option<String>,
slicable: Option<String>,
ident: Option<syn::Ident>,
}
#[derive(Default, Debug)]
struct OptionByField {
renames: HashMap<Ident, String>,
local_branch_prefix: HashMap<Ident, String>,
global_branch_prefix: HashMap<Ident, String>,
absolute_names: HashMap<Ident, String>,
slicables: HashMap<Ident, String>,
}
#[proc_macro_derive(ReadFromTree, attributes(oxyroot))]
pub fn derive_ead_from_tree(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let opts = GOpts::from_derive_input(&input).expect("Wrong options");
let mut opts_by_fiels = OptionByField::default();
let data = opts
.data
.as_ref()
.take_struct()
.expect("should be struct")
.fields;
for f in data.iter() {
let original_name = f.ident.as_ref().expect("de");
let final_name = match &f.rename {
None => original_name.to_string(),
Some(i) => i.to_string(),
};
opts_by_fiels
.renames
.insert(original_name.clone(), final_name);
if let Some(l) = &f.branch_prefix {
opts_by_fiels
.local_branch_prefix
.insert(original_name.clone(), l.to_string());
}
if let Some(g) = &opts.branch_prefix {
opts_by_fiels
.global_branch_prefix
.insert(original_name.clone(), g.to_string());
}
if let Some(a) = &f.absolute_name {
opts_by_fiels
.absolute_names
.insert(original_name.clone(), a.to_string());
}
if let Some(a) = &f.slicable {
opts_by_fiels
.slicables
.insert(original_name.clone(), a.to_string());
}
}
let name = input.ident;
let slicable = opts.slicable.unwrap_or(false);
let generics = add_trait_bounds(input.generics);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let func = write_func_for_readtotree(&input.data, &opts_by_fiels);
let func_sliced = write_func_for_readtotree_sliced(&input.data, &opts_by_fiels);
let stru = write_struct_for_readtotree(&input.data, &opts_by_fiels);
let stru_sliced = write_struct_for_readtotree_sliced(&input.data, &opts_by_fiels);
let next = write_next_for_readtotree(&input.data, &opts_by_fiels);
let next_sliced = write_next_for_readtotree_sliced(name.clone(), &input.data);
let iterator_name = format_ident!("{name}Iterator");
let iterator_name_sliced = format_ident!("{name}IteratorSliced");
let iterator = if slicable {
quote!(
use oxyroot::Slice;
struct #iterator_name_sliced<'a> {
#stru_sliced
}
impl<'a> #iterator_name_sliced<'a> {
fn new(tree: &'a oxyroot::ReaderTree, branch_name: oxyroot::BranchName) -> oxyroot::Result<Self> {
use oxyroot::ReadFromTree;
#func_sliced
}
}
impl Iterator for #iterator_name_sliced<'_> {
type Item = oxyroot::ReadFromTreeResult<#name>;
fn next(&mut self) -> Option<Self::Item> {
#next_sliced
}
}
)
} else {
quote!()
};
let ok = if slicable {
quote!(
Ok(#iterator_name_sliced::new(tree, branch_name)?)
)
} else {
quote!(Ok(#iterator_name::new(tree, branch_name)?))
};
let expanded = quote!(
impl<'a> #impl_generics #ty_generics #where_clause oxyroot::ReadFromTree<'a> for #name{
fn from_branch_tree(tree: &'a oxyroot::ReaderTree,
branch_name: oxyroot::BranchName)
-> oxyroot::Result<impl Iterator<Item = oxyroot::ReadFromTreeResult<#name>> +'a >{
use oxyroot::ReadFromTreeResult;
struct #iterator_name<'a> {
#stru
}
impl<'a> #iterator_name<'a> {
fn new(tree: &'a oxyroot::ReaderTree, branch_name: oxyroot::BranchName) -> oxyroot::Result<Self> {
use oxyroot::ReadFromTree;
#func
}
}
impl Iterator for #iterator_name<'_> {
type Item = oxyroot::ReadFromTreeResult<#name>;
fn next(&mut self) -> Option<Self::Item> {
Some(oxyroot::ReadFromTreeResult::OneValue(#name { #next }))
}
}
Ok(#iterator_name::new(tree, branch_name)?)
}
fn from_branch_tree_sliced(tree: &'a oxyroot::ReaderTree,
branch_name: oxyroot::BranchName)
-> oxyroot::Result<impl Iterator<Item = oxyroot::ReadFromTreeResult<#name>> +'a >{
use oxyroot::ReadFromTreeResult;
struct #iterator_name<'a> {
#stru
}
impl<'a> #iterator_name<'a> {
fn new(tree: &'a oxyroot::ReaderTree, branch_name: oxyroot::BranchName) -> oxyroot::Result<Self> {
use oxyroot::ReadFromTree;
#func
}
}
impl Iterator for #iterator_name<'_> {
type Item = oxyroot::ReadFromTreeResult<#name>;
fn next(&mut self) -> Option<Self::Item> {
Some(oxyroot::ReadFromTreeResult::OneValue(#name { #next }))
}
}
#iterator
#ok
}
}
);
expanded.into()
}
fn add_trait_bounds(mut generics: Generics) -> Generics {
for param in &mut generics.params {
if let GenericParam::Type(ref mut type_param) = *param {
type_param.bounds.push(parse_quote!(oxyroot::ReadFromTree));
}
}
generics
}
fn write_struct_for_readtotree(data: &Data, opts_by_fiels: &OptionByField) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let field_type = &f.ty;
match opts_by_fiels.slicables.get(f.ident.as_ref().unwrap()) {
None => {
quote_spanned! {
f.span() => #field_name: Box<dyn Iterator<Item=oxyroot::ReadFromTreeResult<#field_type>> + 'a>,
}
}
Some(s) => {
let ty = syn::parse_str::<Expr>(s).unwrap();
quote_spanned! {
f.span() => #field_name: Box<dyn Iterator<Item=oxyroot::ReadFromTreeResult<#ty>> + 'a>,
}
}
}
});
quote!(#(#recurse)*)
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
fn write_struct_for_readtotree_sliced(data: &Data, _opts_by_fiels: &OptionByField) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let field_type = &f.ty;
quote_spanned! {
f.span() => #field_name: Box<dyn Iterator<Item=oxyroot::ReadFromTreeResult<Slice<#field_type>>> + 'a>,
}
});
quote!(#(#recurse)*)
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
fn write_func_for_readtotree(data: &Data, opts_by_fiels: &OptionByField) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let branch_names = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let branch_name_ident = format_ident!("bn_{field_name}");
let branch_name = match opts_by_fiels.renames.get(f.ident.as_ref().unwrap()) {
None => field_name.to_string(),
Some(s) => s.to_string(),
};
let mut let_b =
quote_spanned!(f.span() => let b = branch_name.make_child(#branch_name));
let global_prefix = opts_by_fiels
.global_branch_prefix
.get(f.ident.as_ref().unwrap());
if let Some(l) = global_prefix {
let_b = quote_spanned!(f.span() => #let_b.with_prefix(#l));
}
let absolute_name = opts_by_fiels.absolute_names.get(f.ident.as_ref().unwrap());
if let Some(a) = absolute_name {
let_b = quote_spanned!(f.span() => #let_b.make_absolute(#a));
}
let local_prefix = opts_by_fiels
.local_branch_prefix
.get(f.ident.as_ref().unwrap());
if let Some(l) = local_prefix {
let_b = quote_spanned!(f.span() => #let_b.with_prefix(#l));
}
quote_spanned!(f.span() => let #branch_name_ident =
{
#let_b;
b
};
)
});
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let _branch_name = match opts_by_fiels.renames.get(f.ident.as_ref().unwrap()) {
None => { field_name.to_string()}
Some(s) => {s.to_string()}
};
let field_type = &f.ty;
let branch_name_ident = format_ident!("bn_{field_name}");
match opts_by_fiels.slicables.get(f.ident.as_ref().unwrap()) {
None => {
quote_spanned! {
f.span() => #field_name:Box::new(<#field_type>::from_branch_tree(tree, #branch_name_ident.into())?) ,
}
}
Some(s) => {
let ty = syn::parse_str::<Expr>(s).unwrap();
quote_spanned! {
f.span() => #field_name:Box::new(<#ty>::from_branch_tree_sliced(tree, #branch_name_ident.into())?) ,
}
}
}
});
quote!( #(#branch_names)* Ok(Self{ #(#recurse)* }))
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
fn write_func_for_readtotree_sliced(data: &Data, opts_by_fiels: &OptionByField) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let branch_names = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let branch_name_ident = format_ident!("bn_{field_name}");
let branch_name = match opts_by_fiels.renames.get(f.ident.as_ref().unwrap()) {
None => field_name.to_string(),
Some(s) => s.to_string(),
};
let mut let_b =
quote_spanned!(f.span() => let b = branch_name.make_child(#branch_name));
let global_prefix = opts_by_fiels
.global_branch_prefix
.get(f.ident.as_ref().unwrap());
if let Some(l) = global_prefix {
let_b = quote_spanned!(f.span() => #let_b.with_prefix(#l));
}
let absolute_name = opts_by_fiels.absolute_names.get(f.ident.as_ref().unwrap());
if let Some(a) = absolute_name {
let_b = quote_spanned!(f.span() => #let_b.make_absolute(#a));
}
let local_prefix = opts_by_fiels
.local_branch_prefix
.get(f.ident.as_ref().unwrap());
if let Some(l) = local_prefix {
let_b = quote_spanned!(f.span() => #let_b.with_prefix(#l));
}
quote_spanned!(f.span() => let #branch_name_ident =
{
#let_b;
b
};
)
});
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let _branch_name = match opts_by_fiels.renames.get(f.ident.as_ref().unwrap()) {
None => { field_name.to_string()}
Some(s) => {s.to_string()}
};
let field_type = &f.ty;
let branch_name_ident = format_ident!("bn_{field_name}");
quote_spanned! {
f.span() => #field_name:Box::new(<Slice<#field_type>>::from_branch_tree(tree, #branch_name_ident.into())?) ,
}
});
quote!( #(#branch_names)* Ok(Self{ #(#recurse)* }))
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
fn write_next_for_readtotree(data: &Data, opts_by_fiels: &OptionByField) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
match opts_by_fiels.slicables.get(f.ident.as_ref().unwrap()) {
None => {
quote_spanned! {
f.span() => #field_name: self.#field_name.next()?.unwrap(),
}
}
Some(_) => {
quote_spanned! {
f.span() => #field_name: self.#field_name.next()?.unwrap_slice().into(),
}
}
}
});
quote!( #(#recurse)* )
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
fn write_next_for_readtotree_sliced(name: Ident, data: &Data) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let get_sliced = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
quote_spanned! {
f.span() =>
let #field_name = self.#field_name.next()?.unwrap();
let _size_slice = #field_name.inner().len();
}
});
let get_sliced = quote!( #(#get_sliced)* );
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let field_namei = format_ident!("{field_name}i");
quote_spanned! {
f.span() => let #field_namei = #field_name.inner()[i];
}
});
let get_slice_i = quote!( #(#recurse)* );
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let field_namei = format_ident!("{field_name}i");
quote_spanned! {
f.span() => #field_name: #field_namei,
}
});
let ret = quote!( #(#recurse)* );
quote!(
#get_sliced
let mut v = Vec::new();
for i in 0.._size_slice {
#get_slice_i
let p = #name {
#ret
};
v.push(p);
}
Some(oxyroot::ReadFromTreeResult::Slice(Slice::new(v)))
)
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
#[proc_macro_derive(WriteToTree)]
pub fn derive_write_to_tree(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let generics = add_trait_bounds(input.generics);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let send_recv = write_send_recv_for_write_to_tree(&input.data);
let match_it_some = write_match_it_some_for_write_to_tree(&input.data);
let match_it_none = write_match_it_none_for_write_to_tree(&input.data);
let new_branch = write_new_branch_for_write_to_tree(&input.data);
let expanded = quote!(
impl #impl_generics #ty_generics #where_clause oxyroot::WriteToTree for #name{
fn to_branch_tree(
mut it: impl Iterator<Item = #name> + 'static,
tree: &mut oxyroot::WriterTree, branch_name: Option<&str>
) -> oxyroot::Result<()> {
use std::cell::RefCell;
use std::rc::Rc;
struct Channel<T> {
current: Rc<RefCell<Option<T>>>,
}
struct Sender<T> {
channel: Channel<T>,
}
impl<T> Sender<T> {
fn send(&self, value: Option<T>) {
let mut current = self.channel.current.borrow_mut();
*current = value;
}
}
struct Receiver<T> {
channel: Channel<T>,
}
pub fn make_channel<T>() -> (Sender<T>, Receiver<T>) {
let current = Rc::new(RefCell::new(None));
let channel = Channel {
current: current.clone(),
};
let sender = Sender { channel: channel };
let receiver = Receiver {
channel: Channel {
current: current.clone(),
},
};
(sender, receiver)
}
impl<T> Iterator for Receiver<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let mut current = self.channel.current.borrow_mut();
let ret = current.take();
ret
}
}
#send_recv
let func = move |s: oxyroot::StateCallBack| {
match s {
oxyroot::StateCallBack::Before => {
match it.next() {
None => {
#match_it_none
}
Some(struct_instance) => {
#match_it_some
}
};
}
oxyroot::StateCallBack::Branch(_) => {}
oxyroot::StateCallBack::After => {}
}
};
#new_branch
tree.add_callback(Box::new(func));
Ok(())
}
}
);
expanded.into()
}
fn write_send_recv_for_write_to_tree(data: &Data) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let _field_type = &f.ty;
let sender_name = format_ident!("sender_{field_name}");
let recv_name = format_ident!("recv_{field_name}");
quote_spanned! {
f.span() => let (#sender_name, #recv_name) = make_channel();
}
});
quote!(#(#recurse)*)
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
fn write_match_it_some_for_write_to_tree(data: &Data) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let _field_type = &f.ty;
let sender_name = format_ident!("sender_{field_name}");
let _recv_name = format_ident!("recv_{field_name}");
quote_spanned! {
f.span() => #sender_name.send(Some(struct_instance.#field_name));
}
});
quote!(#(#recurse)*)
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
fn write_match_it_none_for_write_to_tree(data: &Data) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let _field_type = &f.ty;
let sender_name = format_ident!("sender_{field_name}");
let _recv_name = format_ident!("recv_{field_name}");
quote_spanned! {
f.span() => #sender_name.send(None);
}
});
quote!(#(#recurse)*)
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}
fn write_new_branch_for_write_to_tree(data: &Data) -> TokenStream {
match &data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => {
let recurse = fields.named.iter().map(|f| {
let field_name = f.ident.as_ref().unwrap();
let field_type = &f.ty;
let _sender_name = format_ident!("sender_{field_name}");
let recv_name = format_ident!("recv_{field_name}");
quote_spanned! {
f.span() => <#field_type>::to_branch_tree(#recv_name.into_iter(), tree, stringify!(#field_name).into())?;
}
});
quote!(#(#recurse)*)
}
Fields::Unnamed(_) => {
unimplemented!("Unnamed")
}
Fields::Unit => {
unimplemented!("Unit")
}
},
Data::Enum(_) => {
unimplemented!("Enum")
}
Data::Union(_) => {
unimplemented!("Union")
}
}
}