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 Borrowable 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?