From c162e63b1d2ba5975dd7f31beeb0bb785ff5f457 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Mon, 10 May 2021 01:50:01 +0200
Subject: [PATCH] sequence map

---
 nested/src/sequence/map.rs | 90 ++++++++++++++++++++++++++++++++++++++
 nested/src/sequence/mod.rs |  1 +
 2 files changed, 91 insertions(+)
 create mode 100644 nested/src/sequence/map.rs

diff --git a/nested/src/sequence/map.rs b/nested/src/sequence/map.rs
new file mode 100644
index 0000000..dc2d1c1
--- /dev/null
+++ b/nested/src/sequence/map.rs
@@ -0,0 +1,90 @@
+use {
+    std::sync::Arc,
+    std::sync::RwLock,
+    crate::{
+        sequence::{SequenceView},
+        core::{
+            Observer, ObserverExt, ObserverBroadcast,
+            View, ViewPort, InnerViewPort, OuterViewPort
+        }
+    }
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
+    pub fn map<
+        DstItem: 'static,
+        F: Fn(&Item) -> DstItem + Send + Sync + 'static
+    >(
+        &self,
+        f: F
+    ) -> OuterViewPort<dyn SequenceView<Item = DstItem>> {
+        let port = ViewPort::new();
+        let map = Arc::new(RwLock::new(MapSequenceItem {
+            src_view: None,
+            f,
+            cast: port.inner().get_broadcast()
+        }));
+
+        self.add_observer(map.clone());
+        port.inner().set_view(Some(map));
+        port.into_outer()
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct MapSequenceItem<DstItem, SrcView, F>
+where SrcView: SequenceView + ?Sized,
+      F: Fn(&SrcView::Item) -> DstItem + Send + Sync
+{
+    src_view: Option<Arc<SrcView>>,
+    f: F,
+    cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = DstItem>>>>
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<DstItem, SrcView, F> View for MapSequenceItem<DstItem, SrcView, F>
+where SrcView: SequenceView + ?Sized,
+      F: Fn(&SrcView::Item) -> DstItem + Send + Sync
+{
+    type Msg = usize;
+}
+
+impl<DstItem, SrcView, F> SequenceView for MapSequenceItem<DstItem, SrcView, F>
+where SrcView: SequenceView + ?Sized,
+      F: Fn(&SrcView::Item) -> DstItem + Send + Sync
+{
+    type Item = DstItem;
+
+    fn len(&self) -> Option<usize> {
+        self.src_view.len()
+    }
+
+    fn get(&self, idx: &usize) -> Option<DstItem> {
+        self.src_view.get(idx).as_ref().map(|item| (self.f)(item))
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<DstItem, SrcView, F> Observer<SrcView> for MapSequenceItem<DstItem, SrcView, F>
+where SrcView: SequenceView + ?Sized,
+      F: Fn(&SrcView::Item) -> DstItem + Send + Sync
+{
+    fn reset(&mut self, view: Option<Arc<SrcView>>) {
+        let old_len = self.len();
+        self.src_view = view;
+        let new_len = self.len();
+
+        if let Some(len) = old_len { self.cast.notify_each(0 .. len ); }
+        if let Some(len) = new_len { self.cast.notify_each(0 .. len ); }
+    }
+
+    fn notify(&self, msg: &usize) {
+        self.cast.notify(msg);
+    }
+}
+
diff --git a/nested/src/sequence/mod.rs b/nested/src/sequence/mod.rs
index 2dda5fa..d0f8366 100644
--- a/nested/src/sequence/mod.rs
+++ b/nested/src/sequence/mod.rs
@@ -1,6 +1,7 @@
 
 pub mod seq2idx;
 pub mod vec_buffer;
+pub mod map;
 pub mod flatten;
 
 pub use {