diff --git a/src/projection/filter_sequence.rs b/src/projection/filter_sequence.rs index a6e2b45..6819e3d 100644 --- a/src/projection/filter_sequence.rs +++ b/src/projection/filter_sequence.rs @@ -135,7 +135,10 @@ where opds.resize_with(1 + *idx, || false); let op = opds.get(*idx).cloned().unwrap_or(false); - *opds.get_mut(*idx).unwrap() = np; + // if let Some(o) = opds.get_mut(*idx) { + // *o = np; + // } + *opds.get_mut(*idx).unwrap() = np; drop(opds); diff --git a/src/projection/mod.rs b/src/projection/mod.rs index b3ae110..d6d3875 100644 --- a/src/projection/mod.rs +++ b/src/projection/mod.rs @@ -23,4 +23,5 @@ pub mod map_index_key; pub mod grid_offset; pub mod decorate_sequence; pub mod reverse_sequence; +pub mod reverse_list; diff --git a/src/projection/reverse_list.rs b/src/projection/reverse_list.rs new file mode 100644 index 0000000..c020233 --- /dev/null +++ b/src/projection/reverse_list.rs @@ -0,0 +1,153 @@ +use { + crate::{ + view::{ + Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort, + list::{ListDiff, ListView, ListViewExt}, + }, + }, + std::sync::Arc, + std::sync::RwLock, +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +impl OuterViewPort> { + pub fn reverse(&self) -> OuterViewPort> { + let port = ViewPort::new(); + port.add_update_hook(Arc::new(self.0.clone())); + + let map = Arc::new(RwLock::new(ReverseList { + src_view: None, + end: 0, + cast: port.inner().get_broadcast(), + })); + + self.add_observer(map.clone()); + port.inner().set_view(Some(map)); + port.into_outer() + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +pub struct ReverseList +where Item: Clone + Send + Sync + 'static, + SrcView: ListView + ?Sized +{ + src_view: Option>, + end: usize, + cast: Arc>>> +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +impl View for ReverseList +where Item: Clone + Send + Sync + 'static, + SrcView: ListView + ?Sized +{ + type Msg = ListDiff; +} + +impl ListView for ReverseList +where Item: Clone + Send + Sync + 'static, + SrcView: ListView + ?Sized +{ + fn len(&self) -> Option { + Some(self.end) + } + + fn get(&self, idx: &usize) -> Option { + if *idx < self.end { + self.src_view.get( &(self.end - idx - 1) ) + } else { + None + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +impl Observer for ReverseList +where Item: Clone + Send + Sync + 'static, + SrcView: ListView + ?Sized +{ + fn reset(&mut self, view: Option>) { + self.src_view = view; + + self.cast.notify(&ListDiff::Clear); + if let Some(v) = self.src_view.as_ref() { + self.end = v.len().unwrap(); + for idx in 0 .. self.end { + if idx < self.end { + let val = v.get( &(self.end - idx - 1) ).unwrap(); + self.cast.notify(&ListDiff::Insert{ idx: idx, val }); + } + } + } + } + + fn notify(&mut self, msg: &ListDiff) { + /* todo optimize + */ + //let len = self.src_view.len().unwrap(); + + self.cast.notify(&match msg { + ListDiff::Clear => { + self.end = 0; + ListDiff::Clear + }, + ListDiff::Remove(mut idx) => { + self.end -= 1; + idx = self.end - idx; + ListDiff::Remove(idx) + } + ListDiff::Insert{ mut idx, val } => { + idx = self.end - idx; + self.end += 1; + ListDiff::Insert{ idx, val:val.clone() } + } + ListDiff::Update{ mut idx, val } => { + idx = self.end - idx - 1; + ListDiff::Update{ idx, val:val.clone() } + } + }); + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +#[cfg(test)] +mod tests { + use crate::buffer::vec::*; + use crate::view::{port::UpdateTask, list::ListView}; + + #[test] + fn rev_list1() { + let mut buffer = VecBuffer::new(); + + let target_port = buffer.get_port().to_list().reverse(); + let target_view = target_port.get_view(); + + buffer.push(0); + buffer.push(7); + buffer.push(9); + + target_port.0.update(); + + assert_eq!(target_view.len(), Some(3)); + + assert_eq!(target_view.get(&0), Some(9)); + assert_eq!(target_view.get(&1), Some(7)); + assert_eq!(target_view.get(&2), Some(0)); + assert_eq!(target_view.get(&3), None); + + buffer.remove(0); + + target_port.0.update(); + assert_eq!(target_view.len(), Some(2)); + assert_eq!(target_view.get(&0), Some(9)); + assert_eq!(target_view.get(&1), Some(7)); + assert_eq!(target_view.get(&2), None); + } +} +