Hello
I needed this feature but I did not want to use nightly so I made a crate that kind of emulates it. Here it is: variant.rs. It is not published yet and probably won't be. I would like opinions about the proc-macro and the uses of unsafe.
Hello
I needed this feature but I did not want to use nightly so I made a crate that kind of emulates it. Here it is: variant.rs. It is not published yet and probably won't be. I would like opinions about the proc-macro and the uses of unsafe.
It would be nice to hear the motivation. Apart from the explicit discriminants, it seems the feature you add is a type-based new and get method. Your use of unreachable! is incorrect, because that branch is certainly reachable.
I haven't looked carefully at the unsafe code, since I don't see a reason for it. What is the value of an explicit discriminant?
It uses a union internally so it needs unsafe when reading from it.
You are right, the unreachable statement was reachable in the constructor is called with an invalid type parameter. I fixed it. Thank you
I find the generic-type based API a bit weird: what happens if two variants share the same type?
I think that adding a constructor for each branch can make it look quite nice. Then, you can try to add some sugar to make pattern-matching more user-friendly. Here is a basic PoC of the idea:
arbitrary_discriminants! {
#[repr(u8)]
/// hi
pub(self)
enum Foo {
_Bar,
Baz(i32) = 42,
_Quux,
}
}
fn main ()
{
let f = Foo::Baz(42);
match_! { f,
Foo::_Bar => {},
Foo::Baz(ft) => println!("{}", ft),
Foo::_Quux => {},
}
}
/// hi
pub(self) struct Foo {
pub tag: FooTag,
pub payload: FooPayload,
}
#[allow(unused_parens)]
impl Foo {
#[allow(nonstandard_style, unused_parens)]
pub fn _Bar() -> Self {
Self{tag: FooTag::_Bar, payload: FooPayload{_Bar: { },},}
}
#[allow(nonstandard_style, unused_parens)]
pub fn Baz(it: i32) -> Self {
Self{tag: FooTag::Baz, payload: FooPayload{Baz: { let _: i32; it },},}
}
#[allow(nonstandard_style, unused_parens)]
pub fn _Quux() -> Self {
Self{tag: FooTag::_Quux, payload: FooPayload{_Quux: { },},}
}
}
#[repr(u8)]
pub(self) enum FooTag { _Bar, Baz = 42, _Quux, }
#[allow(nonstandard_style, unused_parens)]
pub(self) union FooPayload {
_Bar: (),
Baz: (i32),
_Quux: (),
}
fn main() {
let f = Foo::Baz(42);
match f {
e => {
match e.tag {
FooTag::_Bar => {
#[allow(unused_parens)]
let () = unsafe { e.payload._Bar };
{ }
}
FooTag::Baz => {
#[allow(unused_parens)]
let (ft) = unsafe { e.payload.Baz };
println!("{}", ft)
}
FooTag::_Quux => {
#[allow(unused_parens)]
let () = unsafe { e.payload._Quux };
{ }
}
}
}
}
}
Thank you for your answer. I made a new version inspired by your suggestion: link. I went with macro_rules instead of proc_macro, I think it was overkill.