use iced::Rectangle; use iced::futures::channel::mpsc::{UnboundedReceiver, unbounded}; use iced::futures::{StreamExt, stream}; use iced_futures::Subscription; use std::collections::HashMap; use std::fmt::Debug; use std::hash::Hash; use super::RectangleTracker; #[cold] pub fn rectangle_tracker_subscription< I: 'static + Hash + Clone + Send + Sync + Debug, R: 'static + Hash + Clone + Send + Sync + Debug + Eq, >( id: I, ) -> Subscription<(I, RectangleUpdate)> { Subscription::run_with(id, |id| { let id = id.clone(); stream::unfold(State::Ready, move |state| { start_listening(id.clone(), state) }) }) } pub enum State { Ready, Waiting(UnboundedReceiver<(I, Rectangle)>, HashMap), Finished, } async fn start_listening( id: I, mut state: State, ) -> Option<((I, RectangleUpdate), State)> { loop { let (update, new_state) = match state { State::Ready => { let (tx, rx) = unbounded(); ( Some((id.clone(), RectangleUpdate::Init(RectangleTracker { tx }))), State::Waiting(rx, HashMap::new()), ) } State::Waiting(mut rx, mut map) => match rx.next().await { Some(u) => { if let Some(prev) = map.get(&u.0) { let new = u.1; if (prev.width - new.width).abs() > 0.1 || (prev.height - new.height).abs() > 0.1 || (prev.x - new.x).abs() > 0.1 || (prev.y - new.y).abs() > 0.1 { map.insert(u.0.clone(), new); ( Some((id.clone(), RectangleUpdate::Rectangle(u))), State::Waiting(rx, map), ) } else { (None, State::Waiting(rx, map)) } } else { map.insert(u.0.clone(), u.1); ( Some((id.clone(), RectangleUpdate::Rectangle(u))), State::Waiting(rx, map), ) } } None => (None, State::Finished), }, State::Finished => return None, }; state = new_state; if let Some(u) = update { return Some((u, state)); } } } #[derive(Clone, Debug)] pub enum RectangleUpdate where I: 'static + Hash + Clone + Send + Sync + Debug, { Rectangle((I, Rectangle)), Init(RectangleTracker), }