danceinterpreter_rs/
async_utils.rs1use iced::advanced::graphics::futures::{boxed_stream, BoxStream, MaybeSend};
2use iced::advanced::subscription::{from_recipe, EventStream, Hasher, Recipe};
3use iced::futures::stream::FusedStream;
4use iced::futures::{ready, Stream};
5use iced::Subscription;
6use pin_project_lite::pin_project;
7use std::future::Future;
8use std::hash::Hash;
9use std::pin::Pin;
10use std::task::{Context, Poll};
11
12pin_project! {
13 pub struct DroppingOnce<Fut, DropFn>
14 where
15 Fut: Future,
16 DropFn: FnOnce(),
17 {
18 #[pin]
19 future: Option<Fut>,
20 drop_fn: Option<DropFn>,
21 }
22
23 impl<Fut: Future, DropFn: FnOnce()> PinnedDrop for DroppingOnce<Fut, DropFn> {
24 fn drop(this: Pin<&mut Self>) {
25 let this = this.project();
26 if let Some(drop_fn) = this.drop_fn.take() {
27 drop_fn();
28 }
29 }
30 }
31}
32
33impl<Fut: Future, DropFn: FnOnce()> DroppingOnce<Fut, DropFn> {
34 pub fn new(future: Fut, drop_fn: DropFn) -> Self {
35 Self {
36 future: Some(future),
37 drop_fn: Some(drop_fn),
38 }
39 }
40}
41
42impl<Fut: Future, DropFn: FnOnce()> Stream for DroppingOnce<Fut, DropFn> {
43 type Item = Fut::Output;
44
45 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
46 let mut this = self.project();
47 let v = match this.future.as_mut().as_pin_mut() {
48 Some(fut) => ready!(fut.poll(cx)),
49 None => return Poll::Ready(None),
50 };
51
52 this.future.set(None);
53 Poll::Ready(Some(v))
54 }
55
56 fn size_hint(&self) -> (usize, Option<usize>) {
57 if self.future.is_some() {
58 (1, Some(1))
59 } else {
60 (0, Some(0))
61 }
62 }
63}
64
65impl<Fut: Future, DropFn: FnOnce()> FusedStream for DroppingOnce<Fut, DropFn> {
66 fn is_terminated(&self) -> bool {
67 self.future.is_none()
68 }
69}
70
71pub fn run_subscription_with<T, D, S>(data: D, builder: fn(&D) -> S) -> Subscription<T>
73where
74 D: Hash + 'static,
75 S: Stream<Item = T> + MaybeSend + 'static,
76 T: 'static,
77{
78 struct Runner<I, F, S, T>
79 where
80 F: FnOnce(&I, EventStream) -> S,
81 S: Stream<Item = T>,
82 {
83 data: I,
84 spawn: F,
85 }
86
87 impl<I, F, S, T> Recipe for Runner<I, F, S, T>
88 where
89 I: Hash + 'static,
90 F: FnOnce(&I, EventStream) -> S,
91 S: Stream<Item = T> + MaybeSend + 'static,
92 {
93 type Output = T;
94
95 fn hash(&self, state: &mut Hasher) {
96 std::any::TypeId::of::<I>().hash(state);
97 self.data.hash(state);
98 }
99
100 fn stream(self: Box<Self>, input: EventStream) -> BoxStream<Self::Output> {
101 boxed_stream((self.spawn)(&self.data, input))
102 }
103 }
104
105 from_recipe(Runner {
106 data: (data, builder),
107 spawn: |(data, builder), _| builder(data),
108 })
109}