Hey, I stumbled over this while basically building a more generic version of a futures::sink::Sink<_>
wrapper which I already implemented before.
Let me first clarify what I wanted to achieve:
I basically wanted a Sink<_>
(lets call it WrapperSink
) that accepts some Type, let's say Vec<u8>
. This WrapperSink
wraps a generic that should be constrained to Sink
and in particular to a Sink<T>
where T: From<Vec<u8>>
. I had a hard time actually putting this to code. This first thing I came up with was something like this
trait Sink<T> {
fn start_send(&mut self, data: T);
}
struct WrapperSink<S> {
inner_sink: S,
}
impl<S, T> Sink<Vec<u8>> for WrapperSink<S>
where
S: Sink<T>,
T: From<Vec<u8>>
{
fn start_send(&mut self, data: Vec<u8>) {
self.inner_sink.start_send(data.into());
}
}
here I used a simpler version of Sink<_>
. You might immediately see what the problem here is, hence the topic name This fails to compile with the error message
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:11:9
|
11 | impl<S, T> Sink<Vec<u8>> for WrapperSink<S>
| ^ unconstrained type parameter
Since I don't want to waste peoples time I read E0207 (btw. I love this feature ). And sure enough it provided a solution for my problem -> Use PhantomData
.
So sure enough with PhantomData
it works.
use std::marker::PhantomData;
trait Sink<T> {
fn start_send(&mut self, data: T);
}
struct WrapperSink<S, T> {
inner_sink: S,
_phantom: PhantomData<T>
}
impl<S, T> Sink<Vec<u8>> for WrapperSink<S, T>
where
S: Sink<T>,
T: From<Vec<u8>>
{
fn start_send(&mut self, data: Vec<u8>) {
self.inner_sink.start_send(data.into());
}
}
While I should be happy that this works, I'm not really liking this solution. Using the real futures::sink::Sink
that wraps self
into a Pin
requires me to additionally constrain T: Unpin
since PhantomData<T>
is only Unpin
when T: Unpin
(which I honestly don't really understand, after all it should be just a marker?! But I guess that's just a fundamental consequence of the type system. In Addition I'm really not that familiar with Pin
and Unpin
, but that's on my agenda ).
Is there another way to deal with this? Maybe somehow constrain the Type Parameter of the inner Sink
like it would be possible with associated types?
I might be missing the obvious here I just started with Rust again after a very long break. But I was finally able to convince my employer and my colleagues to consider Rust for our new projects, so I'm slowly getting back into it.
Any help or guidance would be really appreciated.