Parse enum from repr[X] enums with values (#769)
* parse enum from repr[X] enums with values * fix parsing negative enums variants with repr[X] * add tests for enum num_value fallback support
This commit is contained in:
parent
5ff6063fe1
commit
087f8462a6
@ -1,7 +1,7 @@
|
||||
use heck::CamelCase;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{punctuated::Punctuated, token::Comma, Lit, LitInt, LitStr, Meta};
|
||||
use syn::{parse, punctuated::Punctuated, token::Comma, Expr, Lit, LitInt, LitStr, Meta, UnOp};
|
||||
|
||||
enum Error {
|
||||
InputNotEnum,
|
||||
@ -128,9 +128,41 @@ impl ActiveEnum {
|
||||
}
|
||||
|
||||
if string_value.is_none() && num_value.is_none() {
|
||||
return Err(Error::TT(quote_spanned! {
|
||||
variant_span => compile_error!("Missing macro attribute, either `string_value` or `num_value` should be specified");
|
||||
}));
|
||||
match variant.discriminant {
|
||||
Some((_, Expr::Lit(exprlit))) => {
|
||||
if let Lit::Int(litint) = exprlit.lit {
|
||||
is_int = true;
|
||||
num_value = Some(litint);
|
||||
} else {
|
||||
return Err(Error::TT(quote_spanned! {
|
||||
variant_span => compile_error!("Enum variant discriminant is not an integer");
|
||||
}));
|
||||
}
|
||||
}
|
||||
//rust doesn't provide negative variants in enums as a single LitInt, this workarounds that
|
||||
Some((_, Expr::Unary(exprnlit))) => {
|
||||
if let UnOp::Neg(_) = exprnlit.op {
|
||||
if let Expr::Lit(exprlit) = *exprnlit.expr {
|
||||
if let Lit::Int(litint) = exprlit.lit {
|
||||
let negative_token = quote! { -#litint };
|
||||
let litint = parse(negative_token.into()).unwrap();
|
||||
|
||||
is_int = true;
|
||||
num_value = Some(litint);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(Error::TT(quote_spanned! {
|
||||
variant_span => compile_error!("Only - token is supported in enum variants, not ! and *");
|
||||
}));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::TT(quote_spanned! {
|
||||
variant_span => compile_error!("Missing macro attribute, either `string_value` or `num_value` should be specified or specify repr[X] and have a value for every entry");
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variants.push(ActiveEnumVariant {
|
||||
|
@ -232,19 +232,40 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn active_enum_derive_signed_integers() {
|
||||
macro_rules! test_int {
|
||||
macro_rules! test_num_value_int {
|
||||
($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
|
||||
#[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = $rs_type, db_type = $db_type)]
|
||||
pub enum $ident {
|
||||
#[sea_orm(num_value = -10)]
|
||||
Negative,
|
||||
#[sea_orm(num_value = 1)]
|
||||
Big,
|
||||
#[sea_orm(num_value = 0)]
|
||||
Small,
|
||||
#[sea_orm(num_value = -10)]
|
||||
Negative,
|
||||
}
|
||||
|
||||
test_int!($ident, $rs_type, $db_type, $col_def);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_fallback_int {
|
||||
($ident: ident, $fallback_type: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
|
||||
#[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = $rs_type, db_type = $db_type)]
|
||||
#[repr(i32)]
|
||||
pub enum $ident {
|
||||
Big = 1,
|
||||
Small = 0,
|
||||
Negative = -10,
|
||||
}
|
||||
|
||||
test_int!($ident, $rs_type, $db_type, $col_def);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_int {
|
||||
($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
|
||||
assert_eq!($ident::Big.to_value(), 1);
|
||||
assert_eq!($ident::Small.to_value(), 0);
|
||||
assert_eq!($ident::Negative.to_value(), -10);
|
||||
@ -264,15 +285,20 @@ mod tests {
|
||||
};
|
||||
}
|
||||
|
||||
test_int!(I8, "i8", "TinyInteger", TinyInteger);
|
||||
test_int!(I16, "i16", "SmallInteger", SmallInteger);
|
||||
test_int!(I32, "i32", "Integer", Integer);
|
||||
test_int!(I64, "i64", "BigInteger", BigInteger);
|
||||
test_num_value_int!(I8, "i8", "TinyInteger", TinyInteger);
|
||||
test_num_value_int!(I16, "i16", "SmallInteger", SmallInteger);
|
||||
test_num_value_int!(I32, "i32", "Integer", Integer);
|
||||
test_num_value_int!(I64, "i64", "BigInteger", BigInteger);
|
||||
|
||||
test_fallback_int!(I8Fallback, i8, "i8", "TinyInteger", TinyInteger);
|
||||
test_fallback_int!(I16Fallback, i16, "i16", "SmallInteger", SmallInteger);
|
||||
test_fallback_int!(I32Fallback, i32, "i32", "Integer", Integer);
|
||||
test_fallback_int!(I64Fallback, i64, "i64", "BigInteger", BigInteger);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn active_enum_derive_unsigned_integers() {
|
||||
macro_rules! test_uint {
|
||||
macro_rules! test_num_value_uint {
|
||||
($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
|
||||
#[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = $rs_type, db_type = $db_type)]
|
||||
@ -283,6 +309,26 @@ mod tests {
|
||||
Small,
|
||||
}
|
||||
|
||||
test_uint!($ident, $rs_type, $db_type, $col_def);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_fallback_uint {
|
||||
($ident: ident, $fallback_type: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
|
||||
#[derive(Debug, PartialEq, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = $rs_type, db_type = $db_type)]
|
||||
#[repr($fallback_type)]
|
||||
pub enum $ident {
|
||||
Big = 1,
|
||||
Small = 0,
|
||||
}
|
||||
|
||||
test_uint!($ident, $rs_type, $db_type, $col_def);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_uint {
|
||||
($ident: ident, $rs_type: expr, $db_type: expr, $col_def: ident) => {
|
||||
assert_eq!($ident::Big.to_value(), 1);
|
||||
assert_eq!($ident::Small.to_value(), 0);
|
||||
|
||||
@ -300,9 +346,14 @@ mod tests {
|
||||
};
|
||||
}
|
||||
|
||||
test_uint!(U8, "u8", "TinyInteger", TinyInteger);
|
||||
test_uint!(U16, "u16", "SmallInteger", SmallInteger);
|
||||
test_uint!(U32, "u32", "Integer", Integer);
|
||||
test_uint!(U64, "u64", "BigInteger", BigInteger);
|
||||
test_num_value_uint!(U8, "u8", "TinyInteger", TinyInteger);
|
||||
test_num_value_uint!(U16, "u16", "SmallInteger", SmallInteger);
|
||||
test_num_value_uint!(U32, "u32", "Integer", Integer);
|
||||
test_num_value_uint!(U64, "u64", "BigInteger", BigInteger);
|
||||
|
||||
test_fallback_uint!(U8Fallback, u8, "u8", "TinyInteger", TinyInteger);
|
||||
test_fallback_uint!(U16Fallback, u16, "u16", "SmallInteger", SmallInteger);
|
||||
test_fallback_uint!(U32Fallback, u32, "u32", "Integer", Integer);
|
||||
test_fallback_uint!(U64Fallback, u64, "u64", "BigInteger", BigInteger);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user