Hi, I'm trying to recreate reactive-streams interfaces with rust traits, but I have some problems with lifetime bounds. Consider the following traits:
pub trait Subscription: Debug + Send + Sync {
fn request(&self, n: usize);
fn cancel(&self);
}
pub trait Subscriber<'a, T>: Debug + Send + Sync {
fn on_subscribe<S: Subscription>(&self, subscription: &'a S);
fn on_next(&self, value: &T);
fn on_error<E: Error>(&self, error: &E);
fn on_complete(&self);
}
pub trait Publisher<'a, T>: Debug + Send + Sync {
fn subscribe<S: Subscriber<'a, T>>(&self, subscriber: &'a S);
}
When I try to implement a simple publisher(e.g. ArrayPublisher) I got some errors:
#[derive(Debug)]
struct ArrayPublisher<T> {
array: Vec<T>,
}
impl<'a, T: Debug + Clone + Send + Sync + 'a> Publisher<'a, T> for ArrayPublisher<T> {
fn subscribe<S: Subscriber<'a, T>>(&self, subscriber: &'a S) {
let subscription = ArraySubscription::new(self.array.to_vec(), subscriber);
subscriber.on_subscribe(&subscription);
}
}
#[derive(Debug, Clone)]
pub struct ArraySubscription<'a, T, S: Subscriber<'a, T>> {
array: Vec<T>,
subscriber: &'a S,
}
impl<'a, T: Debug, S: Subscriber<'a, T>> ArraySubscription<'a, T, S> {
pub fn new(array: Vec<T>, subscriber: &'a S) -> Self {
ArraySubscription { array, subscriber }
}
}
impl<'a, T: Debug + Send + Sync, S: Subscriber<'a, T>> Subscription for ArraySubscription<'a, T, S> {
fn request(&self, n: usize) {
for i in 0..n {
self.subscriber.on_next(&self.array[i]);
}
}
fn cancel(&self) {
unimplemented!();
}
}
The problem is that subscription variable doesn't live long enough(for 'a
lifetime), and of course this make sense, since 'a
is declared in impl
block which lives more than the subscribe fn
. My guess is to use something like Higher-Rank Trait Bounds, but actually I don't know how. I want to be really generic here, since every publisher can have different lifetimes and implementations, any suggestions?