Implement Subscription::with

This commit is contained in:
Héctor Ramón Jiménez 2020-03-05 02:08:53 +01:00
parent 85ee2fc65a
commit a6531c840b
2 changed files with 77 additions and 6 deletions

View File

@ -77,8 +77,6 @@ impl Application for Launcher {
}
}
dbg!(self);
Command::none()
}
@ -88,11 +86,14 @@ impl Application for Launcher {
match example {
Example::Clock(clock) => clock
.subscription()
.map(move |message| Message::Clock(pane, message)),
.with(pane)
.map(|(pane, message)| Message::Clock(pane, message)),
Example::Stopwatch(stopwatch) => stopwatch
.subscription()
.map(move |message| Message::Stopwatch(pane, message)),
Example::Stopwatch(stopwatch) => {
stopwatch.subscription().with(pane).map(
|(pane, message)| Message::Stopwatch(pane, message),
)
}
}
}));

View File

@ -72,6 +72,34 @@ where
self.recipes
}
/// Adds a value to the [`Subscription`] context.
///
/// The value will be part of the identity of a [`Subscription`].
///
/// This is necessary if you want to use multiple instances of the same
/// [`Subscription`] to produce different kinds of messages based on some
/// external data.
///
/// [`Subscription`]: struct.Subscription.html
pub fn with<T>(mut self, value: T) -> Subscription<H, E, (T, O)>
where
H: 'static,
E: 'static,
O: 'static,
T: std::hash::Hash + Clone + Send + Sync + 'static,
{
Subscription {
recipes: self
.recipes
.drain(..)
.map(|recipe| {
Box::new(With::new(recipe, value.clone()))
as Box<dyn Recipe<H, E, Output = (T, O)>>
})
.collect(),
}
}
/// Transforms the [`Subscription`] output with the given function.
///
/// [`Subscription`]: struct.Subscription.html
@ -187,3 +215,45 @@ where
.boxed()
}
}
struct With<Hasher, Event, A, B> {
recipe: Box<dyn Recipe<Hasher, Event, Output = A>>,
value: B,
}
impl<H, E, A, B> With<H, E, A, B> {
fn new(recipe: Box<dyn Recipe<H, E, Output = A>>, value: B) -> Self {
With { recipe, value }
}
}
impl<H, E, A, B> Recipe<H, E> for With<H, E, A, B>
where
A: 'static,
B: 'static + std::hash::Hash + Clone + Send + Sync,
H: std::hash::Hasher,
{
type Output = (B, A);
fn hash(&self, state: &mut H) {
use std::hash::Hash;
std::any::TypeId::of::<B>().hash(state);
self.value.hash(state);
self.recipe.hash(state);
}
fn stream(
self: Box<Self>,
input: BoxStream<'static, E>,
) -> futures::stream::BoxStream<'static, Self::Output> {
use futures::StreamExt;
let value = self.value;
self.recipe
.stream(input)
.map(move |element| (value.clone(), element))
.boxed()
}
}