Я хочу сделать атрибут #[repr] необязательным, если #[repr(type)] не указан, будет использоваться #[repr(u8)] по умолчанию.
(
#[derive($($path:path),+)]
#[repr($repr:ty)]?
$(#[$attr:meta])*
$vis:vis enum $Name:ident {
$(
$(#[$field_attr:meta])*
$variant:ident = $index:tt,
)*
}
) => {
let expr = if $repr {$repr} else {u8};
$crate::macros::paste::paste! {
#[derive(Debug,Clone,Copy,$crate::Serialize_repr,$crate::Deserialize_repr,enum_sql::IntEnumFromSql,enum_sql::IntEnumToSql , $($path),*)]
$(#[$attr])*
#[serde(try_from = "i16", into = "i16")]
#[repr(if $repr { $repr } else { u8 })]
$vis enum $Name {
$(
$(#[$field_attr])*
$variant = $index,
)*
}
};
если атрибут #[repr] не указан, следует использовать атрибут по умолчанию #[repr(u8)]
я устал #[repr(if $repr { $repr } else { u8 })]
но, похоже, это не работает
Вы должны указать, когда аргумент repr предоставляется, а когда нет. В случае "нет" следует заполнить значение по умолчанию и перейти к случаю "есть".
macro_rules! maybe_repr {
( $name:ident : $repr:ty) => { #[repr($repr)] enum $name { V } };
( $name:ident ) => { maybe_repr!($name : u8); };
}
maybe_repr!(U32 : u32);
maybe_repr!(U8);
@江河, если repr
является первым атрибутом, то он не будет конфликтовать, при условии, что регистр с repr
записан первым. Если вы хотите разрешить repr
в любой позиции, вам нужно будет рекурсивно анализировать атрибуты, аналогично tt muncher.
привет @Jmb, спасибо, приятель
Спасибо @hkBst @Jmb и @nerditation Вот мои обновленные макросы
Кажется, там много повторяющегося кода :D
#[macro_export]
macro_rules! int_enum {
(
#[derive($($path:path),+)]
#[repr($repr:ty)]
$(#[$attr:meta])*
$vis:vis enum $Name:ident {
$(
$(#[$field_attr:meta])*
$variant:ident = $index:tt,
)*
}
) => {
$crate::macros::paste::paste! {
#[derive(Debug,Clone,Copy,$crate::Serialize_repr,$crate::Deserialize_repr,enum_sql::IntEnumFromSql,enum_sql::IntEnumToSql , $($path),*)]
#[repr($repr)]
$(#[$attr])*
#[serde(try_from = "i16", into = "i16")]
$vis enum $Name {
$(
$(#[$field_attr])*
$variant = $index,
)*
}
impl $Name {
pub fn as_i16(&self) -> i16 {
use $Name::*;
match self {
$($variant => $index,)*
}
}
}
impl From<$Name> for i16 {
fn from(status: $Name) -> i16 {
status.as_i16()
}
}
impl TryFrom<i16> for $Name {
type Error = $crate::Error;
fn try_from(code: i16) -> $crate::Result<Self> {
use $Name::*;
match code {
$($index => Ok($variant),)*
_ => Err($crate::Error::invalid("invalid_status_code").set_message(format!("unexpected status: {}", code)))
}
}
}
}
};
(
#[derive($($path:path),+)]
$(#[$attr:meta])*
$vis:vis enum $Name:ident {
$(
$(#[$field_attr:meta])*
$variant:ident = $index:tt,
)*
}
) => {
$crate::macros::paste::paste! {
#[derive(Debug,Clone,Copy,$crate::Serialize_repr,$crate::Deserialize_repr,enum_sql::IntEnumFromSql,enum_sql::IntEnumToSql , $($path),*)]
#[repr(u8)]
$(#[$attr])*
#[serde(try_from = "i16", into = "i16")]
$vis enum $Name {
$(
$(#[$field_attr])*
$variant = $index,
)*
}
impl $Name {
pub fn as_i16(&self) -> i16 {
use $Name::*;
match self {
$($variant => $index,)*
}
}
}
impl From<$Name> for i16 {
fn from(status: $Name) -> i16 {
status.as_i16()
}
}
impl TryFrom<i16> for $Name {
type Error = $crate::Error;
fn try_from(code: i16) -> $crate::Result<Self> {
use $Name::*;
match code {
$($index => Ok($variant),)*
_ => Err($crate::Error::invalid("invalid_status_code").set_message(format!("unexpected status: {}", code)))
}
}
}
}
};
(
#[repr($repr:ty)]
$(#[$attr:meta])*
$vis:vis enum $Name:ident {
$(
$(#[$field_attr:meta])*
$variant:ident = $index:tt,
)*
}
) => {
$crate::macros::paste::paste! {
#[derive(Debug,Clone,Copy,$crate::Serialize_repr,$crate::Deserialize_repr,enum_sql::IntEnumFromSql,enum_sql::IntEnumToSql)]
#[repr($repr)]
$(#[$attr])*
$vis enum $Name {
$(
$(#[$field_attr])*
$variant = $index,
)*
}
impl $Name {
pub fn as_i16(&self) -> i16 {
use $Name::*;
match self {
$($variant => $index,)*
}
}
}
impl From<$Name> for i16 {
fn from(status: $Name) -> i16 {
status.as_i16()
}
}
impl TryFrom<i16> for $Name {
type Error = $crate::Error;
fn try_from(code: i16) -> $crate::Result<Self> {
use $Name::*;
match code {
$($index => Ok($variant),)*
_ => Err($crate::Error::invalid("invalid_status_code").set_message(format!("unexpected status: {}", code)))
}
}
}
}
};
(
$(#[$attr:meta])*
$vis:vis enum $Name:ident {
$(
$(#[$field_attr:meta])*
$variant:ident = $index:tt,
)*
}
) => {
$crate::macros::paste::paste! {
#[derive(Debug,Clone,Copy,$crate::Serialize_repr,$crate::Deserialize_repr,enum_sql::IntEnumFromSql,enum_sql::IntEnumToSql)]
#[repr(u8)]
$(#[$attr])*
$vis enum $Name {
$(
$(#[$field_attr])*
$variant = $index,
)*
}
impl $Name {
pub fn as_i16(&self) -> i16 {
use $Name::*;
match self {
$($variant => $index,)*
}
}
}
impl From<$Name> for i16 {
fn from(status: $Name) -> i16 {
status.as_i16()
}
}
impl TryFrom<i16> for $Name {
type Error = $crate::Error;
fn try_from(code: i16) -> $crate::Result<Self> {
use $Name::*;
match code {
$($index => Ok($variant),)*
_ => Err($crate::Error::invalid("invalid_status_code").set_message(format!("unexpected status: {}", code)))
}
}
}
}
}
}
Вам следует определить реализацию только для того случая, который включает явные derive
и repr
, тогда другие случаи смогут вызывать ее. OTOH, в других случаях не требуется явно анализировать всю структуру, и им может сойти с рук $($rest:tt)*
, как только они проанализируют интересующую их часть: игровая площадка
@Jmb Салют!!! Спасибо, сэр
Привет, спасибо, но есть также выражение $(#[$attr:meta])*, которое будет конфликтовать, если вы добавите другой регистр