The string-cache library has a macro (generated by build script with a phf set) like this:
#[macro_export]
macro_rules! atom {
("index") => { $crate::Atom { data: 0x2 } };
("partialdiff") => { $crate::Atom { data: 0x100000002 } };
("additive") => { $crate::Atom { data: 0x200000002 } };
// ...
("style") => { $crate::Atom { data: 0x4dc00000002 } };
}
What’s nice about this macro is that it can be used both as an expression and as a pattern. For example, in html5ever (simplified a bit):
match name {
atom!("select") => if html_elem_named(ancestor, atom!("template")) { return InSelect }
atom!("td") | atom!("th") => if !last { return InCell; },
atom!("tr") => return InRow,
// ...
Each atom represents a string. Strings that are not in the static set (and more than 7 bytes) are represented as a pointer to a reference-counted String in a global hash map. This means that letting users set the data field to an arbitrary value is unsound. In some cases, safe methods of Atom interpret the bits of data as a raw pointer and dereference it.
The typical way to deal with this is to make the field private, and have constructors that either always set data to a valid value or are unsafe. The atom! macro could expand to e.g. unsafe { $crate::Atom::from_data_unchecked(0x4dc00000002) }. But that macro couldn’t be used as a pattern since neither function calls (even const fn) or unsafe blocks are supported in patterns.
However, the only reason to make data private would be to prevent arbitrary writes. Reading it is fine, it’s not secret. (Item privacy is no good for secrets anyway: if an attacker is allowed to write Rust code they can transmute anything and it’s game over.) Would it make sense to add read-only field to the language? Code outside the module could not set that field (like private fields) but they could read it, and more importantly match on it in a pattern.
Or maybe some other language change would help. Unsafe struct fields with unsafe { pat } blocks in patterns to match them? Having the expansion of macro_rules macros follow the privacy rules of the macro definition site rather than that of the expansion site? Supporting const fn calls in patterns?
(Additionally, we would like to use NonZero in Atom, but since its field is private we have the same problem with patterns.)
CC @nox