Add `serde` implementation for `error-stack`
🌟 What is the purpose of this PR?
Create a serde implementation for Report and Frame
🔗 Related links
- #793
🚫 Blocked by
🔍 What does this change?
- [x] serde implementation for
Report
📜 Does this require a change to the docs?
Yes. The docs need to be updated to make users know that a serde serialization is provided.
⚠️ Known issues
🐾 Next steps
- [x] Discuss the format used (#793)
- [x] new attachment
serde - [x] hook based serialization alternative
- [x] Implement Format
- [ ] ~~PR to implement json hook (follow up)~~
- [ ] Documentation
- [ ] Tests
🛡 What tests cover this?
- New unit tests and integration tests are required
❓ How to test this?
- Unit Tests
- Integration/Snapshot Tests
📹 Demo
This PR implements a hook-based serialization (like #794) and a new attachment kind for serde (like attach_printable). I am unsure if we should keep both or decide on one of them.
While serde is more intuitive, the hook-based serialization allows for greater control but is much more explicit. (hook based would enable us to serialize backtraces easily, which isn't possible otherwise)
Libraries could also enable the serde (if wanted) and add their data. At the same time, with the hook-based approach, we would need to explicitly state every serde type that we want to serialize. hook based gives more control to the end user.
@TimDiekmann, what do you think? Keep both? Only keep attach_serializable() or only keep hooks?
The plan is to remove attach_printable when specialization (min_specialization does not allow specialization on traits) has been stabilized. I don't think it's possible to specialize on two different types, if the second type is not a strict subset of the first type, i.e. (abstracting away the actual specialization-structs)
fn attach<T>();
fn attach<T: Display>();
fn attach<T: Serialize>();
It's not possible, because T could be Display + Serialize and adding a T: Display + Serialize does not help here (yet?). Maybe this is possible with negative trait bounds, but as far as I can tell there is no implementation yet.
In these terms, I'd prefer not to add another attach function.
I know that attach_printable is planned for removal once specialization hits. I haven't thought about the ramifications that every type needs to be a strict subset. This, of course, makes this more challenging.
Therefore I will remove all code relating to attach_serializable.
I am pretty new to the concept of specialization in Rust, so here's my question:
Would something like this be possible (with what you linked):
trait SerializeImpl {
fn serialize(&self) -> Option<&dyn erased_serde::Serialize>;
}
unsafe trait FrameImpl: SerializeImpl {
...
}
impl<C> SerializeImpl for ContextFrame<C> where C: Context {
fn serialize(&self) -> Option<&dyn erased_serde::Serialize> {
None
}
}
impl<C> SerializeImpl for ContextFrame<C> where C: Context + serde::Serialize {
fn serialize(&self) -> Option<&dyn erased_serde::Serialize> {
Some(<dyn erased_serde::Serialize>::erase(self.context))
}
}
unsafe impl<C> FrameImpl for ContextFrame<C> where C: Context {
...
}