rust-derive-builder: structured errors instead of `String`
The build method currently returns Result<Foo, String>. But representing errors as String is not very rustic.
It’s also a show-stopper for using derive_builder with #![no_std] on the stable toolchain. The reason is that String on no_std requires the collections crate, which is marked as unstable.
These are already two reasons that representing errors as String is not optimal.
Proposal
Find a way to return structured errors instead of Strings. On std they should implement the usual fmt traits. On no_std they should be compliant with the stable toolchain.
Questions
The main question is, how do we get the structured errors into scope? This is unfortunately not straightforward, since derive_builder is a proc_macro crate.
proc-macrocrate types cannot export any items other than functions tagged with#[proc_macro_derive]currently.
So we need to work around that limitation somehow. These ideas come to my mind right now
- We could add a
derive_builder_commoncrate, which just exports traits / types / impls and must then be imported by any user ofderive_builder. - We could add a flag to
derive_builderto emit the traits / types / impls directly into the target crate. - Each derivation with
derive_buildercould generate unique error definitions for that struct. - Wait until proc_macros can export items.
All these approaches have their own drawbacks.
- 1+2 add boilerplate and complexity for users of
derive_builder. The out-of-the-box experience is a bit impaired. - 3 introduces unnecessary redundancy (and complexity). This might get ugly if a user has multiple derived builders and does pattern matching on the errors.
- 4 sounds like macros 2.0 which will most certainly take quite a while from now to land on stable.
cc @killercup
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 2
- Comments: 16 (9 by maintainers)
I had an idea for this one: We could accept the path to an error type as an attribute and use that in the build function return type.
As long as there’s an
Intoconversion fromStringtocrate::Error, that’d work (or alternatively we could let the user specify both a type and a conversion function).This way,
derive_builderdoesn’t have to export anything, but the deriving type can have its build fn can use its own crate’s error type and still have an autogenerated build method.I’m working on an embedded crate at the moment (no_std and no allocator, so no
String). I may find some time to work on this enhancement. I’ll post an update if I start work.I’d go with 3. I’m not sure how much code for the error type we are talking about, but I’d be surprised if it ended up being more than 50 lines or so, with most of them trait impls.
I wouldn’t worry about the “matching on errors” case, as it’s not really possible right now anyway. (Aside from comparing the strings, which, given a Display impl, users can still do.)