diff --git a/src/projection/list2seq.rs b/src/projection/list2seq.rs new file mode 100644 index 0000000..93c1924 --- /dev/null +++ b/src/projection/list2seq.rs @@ -0,0 +1,159 @@ +use { + crate::{ + view::{ + InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort, + sequence::SequenceView, + list::{ListView, ListDiff} + }, + buffer::vec::VecDiff, + }, + std::sync::Arc, + std::sync::RwLock, +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +/// Adapter View implementing `List` for `Vec` +pub struct List2Seq +where + T: Clone + Send + Sync + 'static, +{ + cur_len: usize, + src_view: Option>>, + cast: Arc>>>, +} + +impl List2Seq +where + T: Clone + Send + Sync + 'static, +{ + pub fn new(port: InnerViewPort>) -> Arc> { + let l2s = Arc::new(RwLock::new(List2Seq { + cur_len: 0, + src_view: None, + cast: port.get_broadcast(), + })); + port.set_view(Some(l2s.clone())); + l2s + } +} + +impl Observer> for List2Seq +where + T: Clone + Send + Sync + 'static, +{ + fn reset(&mut self, view: Option>>) { + let old_len = self.cur_len; + self.src_view = view; + let new_len = if let Some(src_view) = self.src_view.as_ref() { + src_view.len().unwrap_or(0) + } else { + 0 + }; + + self.cur_len = new_len; + self.cast.notify_each(0..std::cmp::max(old_len, new_len)); + } + + fn notify(&mut self, diff: &ListDiff) { + match diff { + ListDiff::Clear => { + self.cast.notify_each(0..self.cur_len); + self.cur_len = 0 + } + ListDiff::Remove(idx) => { + self.cast.notify_each(*idx..self.cur_len); + self.cur_len -= 1; + } + ListDiff::Insert { idx, val: _ } => { + self.cur_len += 1; + self.cast.notify_each(*idx..self.cur_len); + } + ListDiff::Update { idx, val: _ } => { + self.cast.notify(&idx); + } + } + } +} + +impl View for List2Seq +where + T: Clone + Send + Sync + 'static, +{ + type Msg = usize; +} + +impl SequenceView for List2Seq +where + T: Clone + Send + Sync + 'static, +{ + type Item = T; + + fn get(&self, idx: &usize) -> Option { + self.src_view.as_ref()?.get(idx).clone() + } + + fn len(&self) -> Option { + Some(self.cur_len) + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +impl OuterViewPort> +where + T: Clone + Send + Sync + 'static, +{ + pub fn to_sequence(&self) -> OuterViewPort> { + let port = ViewPort::new(); + port.add_update_hook(Arc::new(self.0.clone())); + + let l2s = List2Seq::new(port.inner()); + self.add_observer(l2s.clone()); + port.into_outer() + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> + +#[cfg(test)] +mod tests { + use crate::buffer::vec::VecBuffer; + use crate::view::port::UpdateTask; + + #[test] + fn list_to_seq() { + let mut buf = VecBuffer::::new(); + let seq_view = buf.get_port().to_list().to_sequence(); + + assert_eq!(seq_view.get_view().unwrap().len(), Some(0)); + + buf.push('a'); + + seq_view.0.update(); + assert_eq!(seq_view.get_view().unwrap().len(), Some(1)); + assert_eq!(seq_view.get_view().unwrap().get(&0), Some('a')); + assert_eq!(seq_view.get_view().unwrap().get(&1), None); + + + buf.push('b'); + + seq_view.0.update(); + assert_eq!(seq_view.get_view().unwrap().len(), Some(2)); + assert_eq!(seq_view.get_view().unwrap().get(&0), Some('a')); + assert_eq!(seq_view.get_view().unwrap().get(&1), Some('b')); + assert_eq!(seq_view.get_view().unwrap().get(&2), None); + + + buf.push('c'); + buf.remove(0); + + seq_view.0.update(); + assert_eq!(seq_view.get_view().unwrap().len(), Some(2)); + assert_eq!(seq_view.get_view().unwrap().get(&0), Some('b')); + assert_eq!(seq_view.get_view().unwrap().get(&1), Some('c')); + assert_eq!(seq_view.get_view().unwrap().get(&2), None); + } +} + + diff --git a/src/projection/mod.rs b/src/projection/mod.rs index 9c05c1f..201e305 100644 --- a/src/projection/mod.rs +++ b/src/projection/mod.rs @@ -7,6 +7,7 @@ pub mod vec2seq; pub mod vec2bin; pub mod vec2json; pub mod vec2list; +pub mod list2seq; pub mod seq2idx; pub mod enumerate_sequence; pub mod filter_sequence;