Как использовать атрибут по умолчанию при создании структуры в макросах Rust

Я хочу сделать атрибут #[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 })] но, похоже, это не работает

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
62
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы должны указать, когда аргумент 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);

Привет, спасибо, но есть также выражение $(#[$attr:meta])*, которое будет конфликтовать, если вы добавите другой регистр

江 河 26.06.2024 07:47

@江河, если repr является первым атрибутом, то он не будет конфликтовать, при условии, что регистр с repr записан первым. Если вы хотите разрешить repr в любой позиции, вам нужно будет рекурсивно анализировать атрибуты, аналогично tt muncher.

Jmb 26.06.2024 08:41

привет @Jmb, спасибо, приятель

江 河 26.06.2024 09:21

Спасибо @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 26.06.2024 09:52

@Jmb Салют!!! Спасибо, сэр

江 河 26.06.2024 10:13

Другие вопросы по теме