use { crate::{ core::{ channel::{queue_channel, set_channel, ChannelData, ChannelReceiver, ChannelSender}, port::UpdateTask, Observer, ObserverExt, OuterViewPort, View, }, index::{IndexArea, IndexView}, sequence::SequenceView, singleton::SingletonView, }, std::sync::RwLock, std::{ any::Any, cmp::max, collections::HashMap, hash::Hash, sync::{Arc, Weak}, }, }; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> pub struct ProjectionHelper<ArgKey, P> where ArgKey: Clone + Hash + Eq, P: Send + Sync + 'static, { keepalive: HashMap<ArgKey, (usize, Arc<dyn Any + Send + Sync>)>, proj: Arc<RwLock<Weak<RwLock<P>>>>, update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>, } impl<ArgKey, P> ProjectionHelper<ArgKey, P> where ArgKey: Clone + Hash + Eq, P: Send + Sync + 'static, { pub fn new(update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>) -> Self { ProjectionHelper { keepalive: HashMap::new(), proj: Arc::new(RwLock::new(Weak::new())), update_hooks, } } pub fn set_proj(&mut self, proj: &Arc<RwLock<P>>) { *self.proj.write().unwrap() = Arc::downgrade(proj); } // todo: make this functions generic over the View // this does currently not work because Observer<V> is not implemented for ProjectionArg for *all* V. pub fn new_singleton_arg<Item: 'static>( &mut self, arg_key: ArgKey, port: OuterViewPort<dyn SingletonView<Item = Item>>, notify: impl Fn(&mut P, &()) + Send + Sync + 'static, ) -> Arc<RwLock<Option<Arc<dyn SingletonView<Item = Item>>>>> { port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel())); port.get_view_arc() } pub fn new_sequence_arg<Item: 'static>( &mut self, arg_key: ArgKey, port: OuterViewPort<dyn SequenceView<Item = Item>>, notify: impl Fn(&mut P, &usize) + Send + Sync + 'static, ) -> Arc<RwLock<Option<Arc<dyn SequenceView<Item = Item>>>>> { port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel())); port.get_view_arc() } pub fn new_index_arg<Key: Clone + Send + Sync + 'static, Item: 'static>( &mut self, arg_key: ArgKey, port: OuterViewPort<dyn IndexView<Key, Item = Item>>, notify: impl Fn(&mut P, &IndexArea<Key>) + Send + Sync + 'static, ) -> Arc<RwLock<Option<Arc<dyn IndexView<Key, Item = Item>>>>> { port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, queue_channel())); port.get_view_arc() } pub fn new_arg<V: View + ?Sized + 'static, D: ChannelData<Item = V::Msg> + 'static>( &mut self, arg_key: ArgKey, src_update: Arc<dyn UpdateTask>, notify: impl Fn(&mut P, &V::Msg) + Send + Sync + 'static, (tx, rx): (ChannelSender<D>, ChannelReceiver<D>), ) -> Arc<RwLock<ProjectionArg<P, V, D>>> where V::Msg: Send + Sync, D::IntoIter: Send + Sync + 'static, { self.remove_arg(&arg_key); let arg = Arc::new(RwLock::new(ProjectionArg { src: None, notify: Box::new(notify), proj: self.proj.clone(), rx, tx, })); let mut hooks = self.update_hooks.write().unwrap(); let idx = hooks.len(); hooks.push(src_update); hooks.push(arg.clone()); self.keepalive.insert(arg_key, (idx, arg.clone())); arg } pub fn remove_arg(&mut self, arg_key: &ArgKey) { let mut hooks = self.update_hooks.write().unwrap(); if let Some((idx, _arg)) = self.keepalive.remove(arg_key) { hooks.remove(idx); hooks.remove(idx); for (_, (j, _)) in self.keepalive.iter_mut() { if *j > idx { *j -= 2; } } } } } /// Special Observer which can access the state of the projection on notify /// also handles the reset() pub struct ProjectionArg<P, V, D> where P: Send + Sync + 'static, V: View + ?Sized, D: ChannelData<Item = V::Msg>, D::IntoIter: Send + Sync, { src: Option<Arc<V>>, notify: Box<dyn Fn(&mut P, &V::Msg) + Send + Sync + 'static>, proj: Arc<RwLock<Weak<RwLock<P>>>>, rx: ChannelReceiver<D>, tx: ChannelSender<D>, } impl<P, V, D> UpdateTask for ProjectionArg<P, V, D> where P: Send + Sync + 'static, V: View + ?Sized, D: ChannelData<Item = V::Msg>, D::IntoIter: Send + Sync, { fn update(&self) { if let Some(p) = self.proj.read().unwrap().upgrade() { if let Some(data) = self.rx.try_recv() { for msg in data { //eprintln!("proj update {:?}", msg); (self.notify)(&mut *p.write().unwrap(), &msg); } } } else { //eprintln!("proj update: upgrade fail"); } } } impl<P, V, D> UpdateTask for RwLock<ProjectionArg<P, V, D>> where P: Send + Sync + 'static, V: View + ?Sized, D: ChannelData<Item = V::Msg>, D::IntoIter: Send + Sync, { fn update(&self) { self.read().unwrap().update(); } } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> impl<P, Item, D> Observer<dyn SingletonView<Item = Item>> for ProjectionArg<P, dyn SingletonView<Item = Item>, D> where P: Send + Sync + 'static, D: ChannelData<Item = ()>, D::IntoIter: Send + Sync, { fn reset(&mut self, new_src: Option<Arc<dyn SingletonView<Item = Item>>>) { self.src = new_src; self.notify(&()); } fn notify(&mut self, msg: &()) { self.tx.send(msg.clone()); } } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> impl<P, Item, D> Observer<dyn SequenceView<Item = Item>> for ProjectionArg<P, dyn SequenceView<Item = Item>, D> where P: Send + Sync + 'static, D: ChannelData<Item = usize>, D::IntoIter: Send + Sync, { fn reset(&mut self, new_src: Option<Arc<dyn SequenceView<Item = Item>>>) { let old_len = self.src.len().unwrap_or(0); self.src = new_src; let new_len = self.src.len().unwrap_or(0); self.notify_each(0..max(old_len, new_len)); } fn notify(&mut self, msg: &usize) { self.tx.send(*msg); } } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> impl<P, Key, Item, D> Observer<dyn IndexView<Key, Item = Item>> for ProjectionArg<P, dyn IndexView<Key, Item = Item>, D> where P: Send + Sync + 'static, Key: Clone + Send + Sync, D: ChannelData<Item = IndexArea<Key>>, D::IntoIter: Send + Sync, { fn reset(&mut self, new_src: Option<Arc<dyn IndexView<Key, Item = Item>>>) { let old_area = self.src.area(); self.src = new_src; self.notify(&old_area); self.notify(&self.src.area()) } fn notify(&mut self, msg: &IndexArea<Key>) { self.tx.send(msg.clone()); } }