Add b prefix to string literal in macro_rules?

I have macros that generate FromStr for enum.

macro_rules! define_enum_with_str_values {
    (
        $(#[$outer:meta])*
        enum $Name:ident {
            default = $Default:ident,
            $($Variant:ident => $StrVar:literal),*
                $(,)*
        }
    ) => { ... }
}

define_enum_with_str_values!(enum Foo {
    default = A,
    A => "A", 
    B  => "B"
});

All works fine except in half cases I need convert from bytes instead of string,
and I do not want to waste CPU cycles for from_utf8 call.

So I want to write inside macro_rules:

       impl TryFrom<&[u8]> for $Name {
            type Error = ();
            fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
                match value {
                    $(
                        b$StrVar =>  Ok($Name :: $Variant) , <== HERE ERROR
                    )*
                    _ => Err(()),
                }
            }
        }

and can not get this to comile. So how should I add b prefix to string literal in macros ?

I don't think you can, because the literal token is opaque to the macro.

But for macro-generated code, I think it would be fine just use if conditions:

        impl TryFrom<&[u8]> for $Name {
            type Error = ();
            fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
                $(if value == $StrVar.as_bytes() {
                    return Ok($Name :: $Variant);
                })*
                Err(())
            }
        }
1 Like

You can declare a bunch of constants.

        impl TryFrom<&[u8]> for $Name {
            type Error = ();
            fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
                $(const $Variant: &'static [u8] = $StrVar.as_bytes();)*
                match value {
                    $(
                        $Variant => Ok($Name :: $Variant),
                    )*
                    _ => Err(())
                }
            }
        }
4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.