diff --git a/src/leveled_term_view.rs b/src/leveled_term_view.rs index 6cb04de..5afc27d 100644 --- a/src/leveled_term_view.rs +++ b/src/leveled_term_view.rs @@ -15,12 +15,11 @@ use { //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> pub struct LeveledTermView { - proj_helper: Option>, - src: Arc>, level: usize, - cast: Arc>> + cast: Arc>>, + proj_helper: ProjectionHelper } impl LeveledTermView { @@ -36,25 +35,22 @@ impl LeveledTermView { src_port: OuterViewPort, dst_port: InnerViewPort ) -> Arc> { + let mut proj_helper = ProjectionHelper::new(); + let v = Arc::new(RwLock::new( LeveledTermView { - proj_helper: None, - src: Arc::new(RwLock::new(Option::>::None)), + src: proj_helper.new_index_arg( + src_port, + |p: &mut Self, pos: &Point2| { + p.cast.notify(pos); + }), level: 0, - cast: dst_port.get_broadcast() + cast: dst_port.get_broadcast(), + proj_helper } )); - let mut projection_helper = ProjectionHelper::new(Arc::downgrade(&v)); - - let (src, src_obs) = projection_helper.new_arg( - |p: Arc>, pos: &Point2| { - p.read().unwrap().cast.notify(pos); - }); - - v.write().unwrap().proj_helper = Some(projection_helper); - v.write().unwrap().src = src; - src_port.add_observer(src_obs); + v.write().unwrap().proj_helper.set_proj(&v); dst_port.set_view(Some(v.clone())); v diff --git a/src/projection.rs b/src/projection.rs index 2e7831a..8d8a578 100644 --- a/src/projection.rs +++ b/src/projection.rs @@ -1,12 +1,14 @@ use { std::{ - sync::{Arc, RwLock, Weak}, cmp::{max}, - any::Any + any::Any, + sync::{Arc, RwLock, Weak} + }, + async_std::{ + stream::StreamExt }, - async_std::stream::StreamExt, crate::{ - core::{View, Observer, ObserverExt, channel::{channel, ChannelData, ChannelSender, ChannelReceiver}}, + core::{View, Observer, ObserverExt, OuterViewPort, channel::{channel, ChannelData, ChannelSender, ChannelReceiver}}, singleton::{SingletonView}, sequence::{SequenceView}, index::{IndexView} @@ -17,22 +19,59 @@ use { pub struct ProjectionHelper { keepalive: Vec>, - proj: Weak> + proj: Arc>>> } impl ProjectionHelper

{ - pub fn new(proj: Weak>) -> Self { + pub fn new() -> Self { ProjectionHelper { keepalive: Vec::new(), - proj + proj: Arc::new(RwLock::new(Weak::new())) } } + pub fn set_proj(&mut self, proj: &Arc>) { + *self.proj.write().unwrap() = Arc::downgrade(proj); + } + + // todo: make this functions generic over the View + // this does currently not work because Observer is not implemented for ProjectionArg for *all* V. + + pub fn new_singleton_arg( + &mut self, + port: OuterViewPort>, + notify: impl Fn(&mut P, &()) + Send + Sync + 'static + ) -> Arc>>>> { + let (view, obs) = self.new_arg(notify); + port.add_observer(obs); + view + } + + pub fn new_sequence_arg( + &mut self, + port: OuterViewPort>, + notify: impl Fn(&mut P, &usize) + Send + Sync + 'static + ) -> Arc>>>> { + let (view, obs) = self.new_arg(notify); + port.add_observer(obs); + view + } + + pub fn new_index_arg( + &mut self, + port: OuterViewPort>, + notify: impl Fn(&mut P, &Key) + Send + Sync + 'static + ) -> Arc>>>> { + let (view, obs) = self.new_arg(notify); + port.add_observer(obs); + view + } + pub fn new_arg< V: View + ?Sized + 'static >( &mut self, - notify: impl Fn(Arc>, &V::Msg) + Send + Sync + 'static + notify: impl Fn(&mut P, &V::Msg) + Send + Sync + 'static ) -> ( Arc>>>, Arc>>> @@ -49,8 +88,16 @@ impl ProjectionHelper

{ let proj = self.proj.clone(); async_std::task::spawn(async move { while let Some(msg) = rx.next().await { - let proj = proj.upgrade().unwrap(); - notify(proj, &msg); + if let Some(proj) = proj.read().unwrap().upgrade() { + loop { + if let Ok(p) = proj.try_write().as_mut() { + notify(&mut *p, &msg); + break; + } + + async_std::task::yield_now(); + } + } } }); diff --git a/src/string_editor.rs b/src/string_editor.rs index 5c1b887..6df881a 100644 --- a/src/string_editor.rs +++ b/src/string_editor.rs @@ -119,12 +119,12 @@ pub mod insert_view { }; pub struct StringInsertView { - proj_helper: Option>, - cursor: Arc>, data: Arc>>, cur_pos: usize, - cast: Arc>> + + cast: Arc>>, + proj_helper: ProjectionHelper } impl View for StringInsertView { @@ -169,45 +169,40 @@ pub mod insert_view { data_port: OuterViewPort>, out_port: InnerViewPort ) -> Arc> { + let mut proj_helper = ProjectionHelper::new(); + let proj = Arc::new(RwLock::new( StringInsertView { - proj_helper: None, - cursor: Arc::new(Option::>>::None), - data: Arc::new(RwLock::new(Option::>>::None)), + cursor: proj_helper.new_singleton_arg( + cursor_port, + |s: &mut Self, _msg| { + let old_pos = s.cur_pos; + let new_pos = s.cursor.get(); + s.cur_pos = new_pos; + s.cast.notify_each(GridWindowIterator::from(Point2::new(min(old_pos, new_pos) as i16,0) ..= Point2::new(max(old_pos, new_pos) as i16, 0))) + }), + + data: proj_helper.new_sequence_arg( + data_port, + |s: &mut Self, idx| { + s.cast.notify(&Point2::new( + if *idx < s.cur_pos { + *idx as i16 + } else { + *idx as i16 + 1 + }, + 0 + )); + }), + cur_pos: 0, - cast: out_port.get_broadcast() + cast: out_port.get_broadcast(), + + proj_helper } )); - let mut projection_helper = ProjectionHelper::new(Arc::downgrade(&proj)); - - let (cursor, cursor_obs) = projection_helper.new_arg( - |s: Arc>, _msg| { - let old_pos = s.read().unwrap().cur_pos; - let new_pos = s.read().unwrap().cursor.get(); - s.write().unwrap().cur_pos = new_pos; - s.read().unwrap().cast.notify_each(GridWindowIterator::from(Point2::new(min(old_pos, new_pos) as i16,0) ..= Point2::new(max(old_pos, new_pos) as i16, 0))) - }); - - let (data, data_obs) = projection_helper.new_arg( - |s: Arc>, idx| { - s.read().unwrap().cast.notify(&Point2::new( - if *idx < s.read().unwrap().cur_pos { - *idx as i16 - } else { - *idx as i16 + 1 - }, - 0 - )); - }); - - proj.write().unwrap().proj_helper = Some(projection_helper); - proj.write().unwrap().cursor = cursor; - proj.write().unwrap().data = data; - - cursor_port.add_observer(cursor_obs); - data_port.add_observer(data_obs); - + proj.write().unwrap().proj_helper.set_proj(&proj); out_port.set_view(Some(proj.clone())); proj