use proc_macro::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{Expr, Token};
struct Values {
values: Punctuated<Expr, Token![,]>,
}
impl Parse for Values {
fn parse(input: ParseStream) -> syn::Result<Self> {
let values = Punctuated::parse_terminated(input)?;
if values.is_empty() {
return Err(syn::Error::new(
input.span(),
"alloc_once! needs at least one value to allocate",
));
}
Ok(Values { values })
}
}
#[proc_macro]
pub fn alloc_once(input: TokenStream) -> TokenStream {
let Values { values } = syn::parse_macro_input!(input as Values);
let values = values.iter();
let expanded = quote! {
{
let __alloc_once_value = ( #(#values,)* );
let __alloc_once_cap = ::core::mem::size_of_val(&__alloc_once_value);
let __alloc_once_arena =
::alloc_once::__private::Bump::with_capacity(__alloc_once_cap);
let __alloc_once_ptr: *mut _ = __alloc_once_arena.alloc(__alloc_once_value);
unsafe { ::alloc_once::AllocOnce::__from_parts(__alloc_once_arena, __alloc_once_ptr) }
}
};
expanded.into()
}