3 ms·
What I want is something similar to the switch from lexical to non-lexical lifetimes; but for enums and pattern matching. `@` is a construct depending on lexica
by demurgos 3y ago
What I want is something similar to the switch from lexical to non-lexical lifetimes; but for enums and pattern matching. `@` is a construct depending on lexical scoping
In following code, it would be nice if the second match could use the early return from the first match to avoid extra checks. It would also be nice if it worked across function boundaries. It would help removing boilerplate conversions or some `unreachable!()` branches.
enum Auth { Guest, User(u32), Bot(u32) }
fn check_permissions(Auth &auth) -> Result<Permission, PermissionError> {
match auth {
Auth::Guest => return PermissionError::Unauthorized,
Auth::User(_) | Auth::Bot(_) => { ... }
// ...
match auth {
Auth::User(_) => {...}
Auth::Bot(_) => {...}
// At this point the compiler should know that `Auth::Guest` is not possible
}
- rphln 3y agoOften I wish that: enum Auth { Guest, User(u32), Bot(u32) } was just syntactic sugar for struct Auth::Guest; struct Auth::User(u32); struct Auth::Bot(u32); type Auth = Auth::Guest | Auth::User | Auth::Bot; where `|` denotes an anonymous union. Using enums feel very clunky when you start needing to work with subsets of them.
- demurgos 3y agoI 100% agree. I tried a few workarounds to get the same result, but it quickly gets out of hand. The two main solutions I'm using is to define the individual variants as in your post, and then one enum per union I care about; even with macros it gets very verbose. There's also the problem that it requires explicit conversions (so it's not zero cost). As an alternative, I define a generic enum where each variant corresponds to a generic param and then you can set it to an inhabited type (such as Infallible) when the variant is not possible. Converting is not zero-cost again. You can retrieve the zero cost manually, but then you need to deal with discriminators yourself / the compiler can't help you there. The pattern type work I mentioned earlier would bring us very close to what you have at the end: enum Auth { Guest, User(u32), Bot(u32) } type FullAuth = pattern_type!(Auth, Auth::Guest | Auth::User(_) | Auth::Bot(_)); // useless, but works type IdAuth = pattern_type!(Auth, Auth::User(_) | Auth::Bot(_)); The full enum still needs to be defined. In particular, it serves as the basis the in-memory representation. All the subset can be handled by the compiler though.