use anyhow::{Result, anyhow};
use syn::parse::{Parse, ParseStream};
struct GenerateInput {
attrs: Vec<syn::Attribute>,
vis: syn::Visibility,
name: syn::Ident,
prefix: syn::Ident,
start: u64,
last: u64,
}
fn parse_index(input: ParseStream) -> syn::Result<u64> {
if input.peek(syn::Token![-]) {
return Err(input.error("Negative indices are not supported."));
}
input.parse::<syn::LitInt>()?.base10_parse::<u64>()
}
impl Parse for GenerateInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.call(syn::Attribute::parse_outer)?;
let vis = input.parse()?;
let name = input.parse()?;
input.parse::<syn::Token![,]>()?;
let prefix = input.parse()?;
input.parse::<syn::Token![,]>()?;
let start = parse_index(input)?;
let inclusive = if input.peek(syn::Token![..=]) {
input.parse::<syn::Token![..=]>()?;
true
} else {
input.parse::<syn::Token![..]>()?;
false
};
let end = parse_index(input)?;
let last = if inclusive {
end
} else {
end
.checked_sub(1)
.ok_or_else(|| input.error("The range produces no variants."))?
};
if start > last {
return Err(input.error("The range produces no variants."));
}
Ok(GenerateInput {
attrs,
vis,
name,
prefix,
start,
last,
})
}
}
pub fn try_generate_enumoid(
input: proc_macro::TokenStream,
) -> Result<proc_macro2::TokenStream> {
let GenerateInput {
attrs,
vis,
name,
prefix,
start,
last,
} = syn::parse(input).map_err(|e| anyhow!("{}", e))?;
let variants = (start..=last)
.map(|i| format_ident!("{}{}", prefix, i))
.collect::<Vec<_>>();
Ok(quote! {
#[derive(Enumoid)]
#(#attrs)*
#vis enum #name {
#(#variants),*
}
})
}