tailhook/quick-error

support for struct-like variants?

Closed this issue ยท 6 comments

This is a great library. ๐Ÿ‘

One thing I am missing is struct-like variants:

quick_error! {
    #[derive(Debug)]
    pub enum IoWrapper {
        IoAt(place: &'static str, err: io::Error) {}
    }
}

let err = IoWrapper::IoAt {
    place: unimplemented!(),
    err: unimplemented!()
}  // compile error: `IoWrapper::IoAt` does not name a structure 

Support for struct-like variants would be great AND it would help migrating some existing error definitions to quick-error.

I just checked: std-lib uses struct-like variants for some error enums too:

  • std::str::Utf8Error
  • std::sync::PoisonError
  • std::string::FromUtf8Error

So there seem to be use cases to use both kind of variants. Is it generally possible to implement at all? If so, the syntax could be curly-braces IoAt{place: ..} {} instead of round-braces IoAt(place: ..) {}.

While the syntax is slightly ambiguous ( Variant { display(...) } is a singleton variant with a body), still I think this is possible. It's on my to-do list, but I'm not sure when I can find some time to implement it.

Yes this is true. You could remove this ambiguity by changing the syntax to something like Variant => { display(...) } - i.e. introducing => inbetween. This would feel quite rusty to me, but it would be a breaking change. :-/

As a preparation I merged the enum [] and items [] buffer into one buffer in #9.

    (SORT [enum $name:ident $(#[$meta:meta])* ]
        items [ $( $(#[$imeta:imeta])*
                  => $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))*
                                { $($ifuncs:tt)* } )* ]
  // ...

I now see two options:
(A)

    (SORT [enum $name:ident $(#[$meta:meta])* ]
        struct_items [ $( $(#[$imeta:imeta])*
                  => $iitem:ident $(( $($ivar:ident : $ityp:ty),* ))*
                                { $($ifuncs:tt)* } )* ]
        tuple_items [ $( $(#[$imeta:imeta])*
                  => $iitem:ident $({ $($ivar:ident : $ityp:ty),* })+
                                { $($ifuncs:tt)* } )* ]
  // ...

(B)

    (SORT [enum $name:ident $(#[$meta:meta])* ]
        items [ $( $(#[$imeta:imeta])*
                  => $iitem:ident $(( $($tuple_var:ident : $tuple_typ:ty),* ))*
                                  $({ $($struct_var:ident : $struct_typ:ty),* })*
                                { $($ifuncs:tt)* } )* ]
  // ...

I think (A) is less ambigous - but it has a very verbose signature. How would you approach struct-like-variants?

Well, both are okay for me. Whichever will actually work :) If both work, I would prefer the one which keeps order of items the same. (I guess the one with struct_items/tuple_items may reorder the enum where tuple and struct items are intermixed). If both are, then I don't care much :)

Ok, I will try (C)

    (SORT [$($def:tt)*]
        items [ $( $(#[$imeta:meta])*
                  => $iitem:ident : $imode:tt $(( $($ivar:ident : $ityp:ty),* ))*
                                { $($ifuncs:tt)* } )* ]

where $imode:tt will be either TUPLE or STRUCT. I am confident it will work - but let's see...

thx :-)