#![no_std]
mod implementation;
mod match_arm;
mod match_attribute;
mod top_level_attribute;
mod utils;
extern crate proc_macro;
use core::panic;
#[cfg(feature = "runtime_configurable")]
mod runtime_configurable;
use proc_macro2::TokenStream;
use syn::{parse2, parse_macro_input, spanned::Spanned, ItemEnum, Meta};
use implementation::{get_match_attrs_per_type, implement_full, implement_partial};
use top_level_attribute::TopLevelAttribute;
#[cfg(feature = "runtime_configurable")]
use runtime_configurable::{declare_runtime_configurable, implement_runtime_configurable};
const ATTR_NAME: &str = "matched_enum";
fn derive_ranged_impl(enum_type: ItemEnum) -> syn::Result<TokenStream> {
let attribute = enum_type
.attrs
.iter()
.find(|attr| attr.path().is_ident(ATTR_NAME))
.map(|attr| match &attr.meta {
Meta::List(members) => parse2::<TopLevelAttribute>(members.tokens.clone()),
_ => Err(syn::Error::new(
enum_type.span(),
format_args!(
"Must provide {ATTR_NAME} as a list. (e.g., `#[{ATTR_NAME}(key=val, ..)]`)"
),
)),
})
.unwrap_or(Ok(TopLevelAttribute::default()))?;
if attribute.value_types.is_empty() {
panic!("`value_types` may not be empty");
}
let matchers_per_type = get_match_attrs_per_type(&enum_type, &attribute)?;
if matchers_per_type.is_empty() {
panic!("Failed to register any type.");
}
let mut stream = TokenStream::default();
#[cfg(feature = "runtime_configurable")]
if attribute.allow_runtime_configurable {
stream.extend(declare_runtime_configurable(&enum_type));
}
for (type_spec, match_pairs) in matchers_per_type.iter() {
stream.extend(if attribute.use_partial_matching {
implement_partial(&enum_type, type_spec, match_pairs)
} else {
implement_full(&enum_type, type_spec, match_pairs)
});
#[cfg(feature = "runtime_configurable")]
if attribute.allow_runtime_configurable {
stream.extend(implement_runtime_configurable(
&enum_type,
type_spec,
match_pairs,
));
}
}
Ok(stream)
}
#[proc_macro_derive(Matched, attributes(matches, matched_enum))]
pub fn derive_ranged(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
derive_ranged_impl(parse_macro_input!(stream as ItemEnum))
.unwrap_or_else(|err| panic!("{err}"))
.into()
}