Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Ideal representation of Error #51

Open
withoutboats opened this issue Nov 17, 2017 · 4 comments
Open

Ideal representation of Error #51

withoutboats opened this issue Nov 17, 2017 · 4 comments

Comments

@withoutboats
Copy link
Contributor

In theory, error could:

  1. Be 1 pointer in size.
  2. Never allocate if backtraces are turned off & the failure is a ZST.

To accomplish this goal, error would look like this:

struct Error {
     inner: usize,
}

This usize would be a pointer to a heap allocation or a vtable. Which kind of pointer it is would be stored using the extra bits of space that alignment guarantees give us on each platform.

The heap allocation would have this layout:

struct Inner {
    vtable: &'static (),
    backtrace: Backtrace,
    data: Fail, // A DST
}

I'm not sure its even possible to write this with unsafe code on stable Rust.

cc @cramertj @dtolnay #9 #20.

@cramertj
Copy link

AFAIK, you'll need double-boxing if you want to store unsized data with a single-width pointer. Presumably you're getting the size to dealloc from vtable? I don't believe there's a user-facing way to free an object of a dynamic size, but @dtolnay would know better.

You could still do struct Inner { backtrace: Backtrace, data: Box<Fail> }.

@withoutboats
Copy link
Contributor Author

withoutboats commented Nov 17, 2017

AFAIK, you'll need double-boxing if you want to store unsized data with a single-width pointer.

Aren't we essentially going to be leaking the data (because of the bitmasking) and then reconstructing the address of it every time? We can make the second pointer null (and then swap it with the vtable pointer)?

Stuff about how to free the object is a good question, we would probably want to store the size inline.

@withoutboats
Copy link
Contributor Author

Basically what we're talking about doing is reimplementing dynamic dispatch in unsafe code instead of using real trait objects.

@withoutboats
Copy link
Contributor Author

This isn't really related but its also about doing unsafe vtable shenanigans:

it would be great to be able to follow the std::error::Error::cause chain to its conclusion instead of just bottoming out at the first non-Fail error we come to. We could do that if we could manufacture a fake vtable somehow.

The Fail vtable has two methods: backtrace (which in the fake one would use the default implementation) and cause. cause is the tricky method. We'd have to call the std::Error::Error::cause method from the original vtable and then perform this very same vtable swap on the result.

No idea how to implement this even if it were possible on stable today.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants