Rationale for AtomCore trait #36
Replies: 2 comments
-
|
Ideally, you would like to use some form of deref magic and place all the methods in pub trait Deref {
type Target: ?Sized;
// Required method
fn deref(&self) -> &Self::Target;
}It requires that the output of deref ( enum Atom(...)
enum AtomView<'a>(...)we cannot construct an There is an RFC that would allow a conversion like this. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for the explanation and the interesting link. This reminds me of a discussion I once started on the Rust user forum. It turns out that there are good reasons why the I think that I understand why you need I haven’t thought deeply about this, but wouldn’t the following alternative design work as well? (I’m not proposing any change, just thinking aloud while trying to understand the rationale for the chosen design.) Instead of the current pairs of types like // It might seem attractive to replace the bound `T: AsRef<[u8]>` below by `T: Deref<Target=[u8]>`.
// This would not work, because while slices implement AsRef to themselves, they do not implement
// Deref to themselves. Thus, AddCore<[u8]> would not be possible.
#[repr(transparent)]
pub struct AddCore<T: ?Sized + AsRef<[u8]>>(T);
pub type AddView = AddCore<[u8]>;
pub type Add = AddCore<Vec<u8>>;Most methods would be implemented for // A reference to AddView can be cheaply obtained from any AddCore<T>.
impl<T: ?Sized + AsRef<[u8]>> AsRef<AddView> for AddCore<T> {
fn as_ref(&self) -> &AddView {
let data = self.0.as_ref();
// SAFETY: This relies on AddCore having #[repr(transparent)].
unsafe { &*(data as *const [u8] as *const AddView) }
}
}
// There’s no ?Sized bound to avoid infinite deref recursion.
impl<T: AsRef<[u8]>> std::ops::Deref for AddCore<T> {
type Target = AddView;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}The crucial difference to the current design is that what is now Now it would be nice if one could define enum AtomCore<T: ?Sized + AsRef<[u8]>> {
Add(AddCore<T>),
// ...
}but unfortunately this does not work (I believe that there is no fundamental reason why this cannot be made to work, it would just require allowing enum-DSTs in the language/compiler...) But we can implement an enum manually: enum AtomKind {
Add,
// ...
}
struct AtomCore<T: ?Sized + AsRef<[u8]>> {
kind: AtomKind,
data: T,
}
// ...I happen to use an analogous design for a different use case. Just curious whether you might find it useful... It was discussed here. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello, thanks for this nice crate. While looking at symbolica, I stumbled across the following design choice. Perhaps someone will be so kind to explain the rationale?
The
AtomCoretrait has a single required methodIn other words, implementing
AtomCoremeans that the type in question can be seen as anAtomView.What if the provided methods of the
AtomCoretrait were simply methods ofAtomViewandAtomCoredidn’t even exist? Types that implementAtomCorecould instead deref toAtomView. What is the rationale for the more complicated design used in symbolica?Beta Was this translation helpful? Give feedback.
All reactions