I have what I consider to be a very simple problem. Consider the following library.
pub trait Foo {}
Now consider the following binary (for which Foo
is external).
struct FooWrapperNewtype<T>(T);
I either want T
to implement library::Foo
, or to be a pointer to a type that implements Foo
. How do I do this? I have tried a number of approaches:
BorrowMut
Here is the closest I came to a solution using BorrowMut
:
struct FooWrapperNewtype<X: ?Sized + Foo, T: std::borrow::BorrowMut<X>>(T);
However, it fails to compile:
error[E0392]: parameter `X` is never used
--> src/lib.rs:2:26
|
2 | struct FooWrapperNewtype<X: ?Sized + Foo, T: std::borrow::BorrowMut<X>>(T);
| ^ unused parameter
|
= help: consider removing `X`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
I believe this is due to the variance rules defined in RFC 738. Might this be an oversight in that RFC?
DerefMut
The following successfully compiles:
trait Foo {}
struct FooWrapperNewtype<T: std::ops::DerefMut>(T) where T::Target: Foo;
However, this doesn't work for types that directly implement Foo
(and not DerefMut
).
Box<dyn Foo>
struct FooWrapperNewtype(Box<dyn Foo>);
This requires object safety, heap allocation, and dynamic dispatch. Next!
Owned wraper around DerefMut
I am unsure if this has been proposed before, but I could not find any similar proposal.
First, the following code (with much better names) could be added to either std
or just an external crate:
/// Identical to `Deref`.
pub trait Wrapper {
type Target: ?Sized;
fn wrapped(&self) -> &Self::Target;
}
/// Identical to `DerefMut`.
pub trait WrapperMut: Wrapper {
fn wrapped_mut(&mut self) -> &mut Self::Target;
}
impl<T: std::ops::Deref> Wrapper for T {
type Target = T::Target;
fn wrapped(&self) -> &Self::Target {
self
}
}
impl<T: std::ops::DerefMut> WrapperMut for T {
fn wrapped_mut(&mut self) -> &mut Self::Target {
self
}
}
pub struct Owned<T>(pub T);
impl<T> Wrapper for Owned<T> {
type Target = T;
fn wrapped(&self) -> &Self::Target {
&self.0
}
}
impl<T> WrapperMut for Owned<T> {
fn wrapped_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
Now you can do the following:
struct FooWrapperNewtype<T: WrapperMut>(T) where T::Target: Foo;
// You can use `FooWrapperNewtype(Owned(...))`
Wrapper
and WrapperMut
are identical to Deref
and DerefMut
respectively, but they omit the implication of a small struct that acts as a smart pointer. They are essentially explicit versions of Deref
/DerefMut
, kind of like how Clone
is essentially(-ish) an explicit version of Copy
. This enables the use of Owned
for types where it makes sense to have a generic Borrow
able type.
If this were to be included in std
, an alternative to the headache of duplicate Wrapper
and Deref
traits could be (in the next edition change) making Deref
a subtrait of Wrapper
(essentially just a marker trait).
Is there any better way to do this, and has the Wrapper
/Owned
solution been proposed somewhere before?