use syn::{Expr, Ident, ItemEnum};
use crate::parse::Parsed;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub(crate) struct ValueExpr {
pub(crate) base: Option<Expr>,
pub(crate) offset: u64,
}
impl ValueExpr {
fn new() -> Self {
Default::default()
}
fn from_expr(expr: Expr) -> Self {
Self {
base: Some(expr),
offset: 0,
}
}
fn next(&self) -> Self {
Self {
base: self.base.clone(),
offset: self.offset + 1,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct ValueExprMatch(pub(crate) Ident, pub(crate) ValueExpr);
pub(crate) struct Transformed {
pub(crate) repr_type: Ident,
pub(crate) variants: Vec<ValueExprMatch>,
pub(crate) item: ItemEnum,
}
pub(crate) fn transform(ast: Parsed) -> Transformed {
let Parsed {
attr: repr_type,
item,
} = ast;
let mut variants = Vec::with_capacity(item.variants.len());
let mut value = ValueExpr::new();
for variant in item.variants.iter() {
if let Some((_, ref expr)) = variant.discriminant {
value = ValueExpr::from_expr(expr.clone());
}
variants.push(ValueExprMatch(variant.ident.clone(), value.clone()));
value = value.next();
}
Transformed {
repr_type,
variants,
item,
}
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::*;
#[test]
fn builds_model_for_enum_with_u16_repr() {
let ast = Parsed {
attr: parse_quote!(u16),
item: parse_quote!(
enum Fieldless {
Zeroth,
First = 2 * 7,
Second,
Third = 1,
}
),
};
let model = transform(ast);
assert!(matches!(model.repr_type.to_string().as_str(), "u16"));
assert_eq!(model.variants.len(), 4);
assert_eq!(
model.variants[0],
ValueExprMatch(
parse_quote!(Zeroth),
ValueExpr {
base: None,
offset: 0,
}
)
);
assert_eq!(
model.variants[1],
ValueExprMatch(
parse_quote!(First),
ValueExpr {
base: Some(parse_quote! {2 * 7}),
offset: 0,
}
)
);
assert_eq!(
model.variants[2],
ValueExprMatch(
parse_quote!(Second),
ValueExpr {
base: Some(parse_quote! {2 * 7}),
offset: 1,
}
)
);
assert_eq!(
model.variants[3],
ValueExprMatch(
parse_quote!(Third),
ValueExpr {
base: Some(parse_quote! {1}),
offset: 0,
}
)
);
}
}