I would like to write a macro_rules!
macro whose arguments are one ident
and a list of string literals. The expansion of the macro needs to contain both the string literals, and the corresponding byte literals. The macro is for tests, and will only ever be used with strings containing only characters in the U+0000 ... U+007F range. It is OK if supplying anything other than string literals to the macro causes a compile-time error.
If this isn't currently possible without resorting to procedural macros, just tell me so, don't bother actually writing the procedural macro ;-)
The desired invocation and expansion is like this:
all_s! isalpha [ "abcdefghijklmnopqrstuvwxyz" /* , ... */ ];
=>
assert!(isalpha("abcdefghijklmnopqrstuvwxyz"));
assert!("abcdefghijklmnopqrstuvwxyz".chars().all(|b| isalpha(b));
assert!(isalpha(b"abcdefghijklmnopqrstuvwxyz"));
assert!(b"abcdefghijklmnopqrstuvwxyz".iter().all(|b| isalpha(b)));
/* ... */
This is as far as I've gotten:
macro_rules! all_s {
($what: ident, $( $str: tt ),* ) => {{
$(
assert!($what($str));
assert!($str.chars().all(|b| $what(b));
assert!($what(BYTE_LITERAL!($str)));
assert!(BYTE_LITERAL!($str).iter().all(|b| $what(b)));
)*
}}
}
but I don't know what to put where it says BYTE_LITERAL!
, and also I'm getting error messages that suggest that I haven't written the match pattern correctly, e.g. "macro all_s! expects no ident argument, given 'isalpha'" when '$what:ident' is right there.
You cannot convert a literal to another type of literal; it's just not how macros work.
You can convert a &str
to a &[u8]
via str::as_bytes
:
fn is_alpha<T>(_: T) -> bool { true }
macro_rules! all_s {
($what: ident, $str: tt) => {{
assert!($what($str));
assert!($str.chars().all(|b| $what(b)));
assert!($what($str.as_bytes()));
assert!($str.as_bytes().iter().all(|b| $what(b)));
}};
}
fn main() {
all_s!(is_alpha, "abcdefghijklmnopqrstuvwxyz");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With