From a9550600f41c0247015c363e8ad33abb72d5417b Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sat, 7 Jan 2023 04:30:16 +0100
Subject: [PATCH] singleton: add flatten() & to_sequence()

---
 nested/src/core/port.rs             |  8 +++
 nested/src/singleton/flatten.rs     | 88 +++++++++++++++++++++++++++++
 nested/src/singleton/mod.rs         |  3 +-
 nested/src/singleton/to_sequence.rs | 77 +++++++++++++++++++++++++
 4 files changed, 175 insertions(+), 1 deletion(-)
 create mode 100644 nested/src/singleton/flatten.rs
 create mode 100644 nested/src/singleton/to_sequence.rs

diff --git a/nested/src/core/port.rs b/nested/src/core/port.rs
index b20ec50..b148e04 100644
--- a/nested/src/core/port.rs
+++ b/nested/src/core/port.rs
@@ -221,6 +221,14 @@ where
     }
 }
 
+impl<V: View + ?Sized> Default for OuterViewPort<V>
+where V::Msg: Clone
+{
+    fn default() -> Self {
+        ViewPort::new().into_outer()
+    }
+}
+
 /*
 impl<V: View + ?Sized + 'static> OuterViewPort<V>
 where V::Msg: Clone {
diff --git a/nested/src/singleton/flatten.rs b/nested/src/singleton/flatten.rs
new file mode 100644
index 0000000..f536416
--- /dev/null
+++ b/nested/src/singleton/flatten.rs
@@ -0,0 +1,88 @@
+use {
+    crate::{
+        core::{
+            port::UpdateTask, InnerViewPort, Observer, ObserverBroadcast, ObserverExt,
+            OuterViewPort, View, ViewPort,
+        },
+        projection::ProjectionHelper,
+        singleton::SingletonView,
+    },
+    std::sync::RwLock,
+    std::{collections::BTreeMap, sync::Arc},
+};
+
+impl<Item> OuterViewPort<dyn SingletonView<Item = OuterViewPort<dyn SingletonView<Item = Item>>>>
+where
+    Item: 'static + Default,
+{
+    pub fn flatten(&self) -> OuterViewPort<dyn SingletonView<Item = Item>> {
+        let port = ViewPort::new();
+        Flatten::new(self.clone(), port.inner());
+        port.into_outer()
+    }
+}
+
+pub struct Flatten<Item>
+where
+    Item: 'static + Default,
+{
+    outer: Arc<dyn SingletonView<Item = OuterViewPort<dyn SingletonView<Item = Item>>>>,
+    inner: OuterViewPort<dyn SingletonView<Item = Item>>,
+    cast: Arc<RwLock<ObserverBroadcast<dyn SingletonView<Item = Item>>>>,
+    proj: ProjectionHelper<usize, Self>
+}
+
+impl<Item> View for Flatten<Item>
+where
+    Item: 'static + Default,
+{
+    type Msg = ();
+}
+
+impl<Item> SingletonView for Flatten<Item>
+where
+    Item: 'static + Default,
+{
+    type Item = Item;
+
+    fn get(&self) -> Self::Item {
+        if let Some(i) = self.inner.get_view() {
+            i.get()
+        } else {
+            Item::default()
+        }
+    }
+}
+
+impl<Item> Flatten<Item>
+where
+    Item: 'static + Default,
+{
+    pub fn new(
+        top_port: OuterViewPort<
+            dyn SingletonView<Item = OuterViewPort<dyn SingletonView<Item = Item>>>,
+        >,
+        out_port: InnerViewPort<dyn SingletonView<Item = Item>>,
+    ) -> Arc<RwLock<Self>> {
+        let mut proj = ProjectionHelper::new(out_port.0.update_hooks.clone());
+
+        let flat = Arc::new(RwLock::new(Flatten {
+            outer: proj.new_singleton_arg(0, top_port, |s: &mut Self, _msg| {
+                s.inner = s.outer.get();
+                s.proj.new_singleton_arg(1, s.inner.clone(), |s: &mut Self, _msg| {
+                    s.cast.notify(&());
+                });
+                //s.inner.0.update();
+            }),
+            inner: OuterViewPort::default(),
+            cast: out_port.get_broadcast(),
+            proj,
+        }));
+
+        flat.write().unwrap().proj.set_proj(&flat);
+        out_port.set_view(Some(flat.clone()));
+        flat
+    }
+}
+
+
diff --git a/nested/src/singleton/mod.rs b/nested/src/singleton/mod.rs
index 0008f4f..c0b9292 100644
--- a/nested/src/singleton/mod.rs
+++ b/nested/src/singleton/mod.rs
@@ -1,7 +1,8 @@
 pub mod buffer;
 pub mod map;
+pub mod flatten;
 pub mod to_index;
-//pub mod unwrap;
+pub mod to_sequence;
 
 use {
     crate::core::View,
diff --git a/nested/src/singleton/to_sequence.rs b/nested/src/singleton/to_sequence.rs
new file mode 100644
index 0000000..c69c038
--- /dev/null
+++ b/nested/src/singleton/to_sequence.rs
@@ -0,0 +1,77 @@
+use {
+    crate::{
+        core::{Observer, ObserverBroadcast, OuterViewPort, View, ViewPort},
+        sequence::{SequenceView},
+        singleton::SingletonView,
+    },
+    std::sync::Arc,
+    std::sync::RwLock,
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
+    pub fn to_sequence(&self) -> OuterViewPort<dyn SequenceView<Item = Item>> {
+        let port = ViewPort::new();
+        port.add_update_hook(Arc::new(self.0.clone()));
+
+        let map = Arc::new(RwLock::new(Singleton2Sequence {
+            src_view: None,
+            cast: port.inner().get_broadcast(),
+        }));
+
+        self.add_observer(map.clone());
+        port.inner().set_view(Some(map));
+        port.into_outer()
+    }    
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct Singleton2Sequence<SrcView>
+where
+    SrcView: SingletonView + ?Sized,
+{
+    src_view: Option<Arc<SrcView>>,
+    cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = SrcView::Item>>>>,
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<SrcView> View for Singleton2Sequence<SrcView>
+where
+    SrcView: SingletonView + ?Sized,
+{
+    type Msg = usize;
+}
+
+impl<SrcView> SequenceView for Singleton2Sequence<SrcView>
+where
+    SrcView: SingletonView + ?Sized,
+{
+    type Item = SrcView::Item;
+
+    fn get(&self, _idx: &usize) -> Option<Self::Item> {
+        Some(self.src_view.as_ref().unwrap().get())
+    }
+
+    fn len(&self) -> Option<usize> {
+        Some(1)
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+impl<SrcView> Observer<SrcView> for Singleton2Sequence<SrcView>
+where
+    SrcView: SingletonView + ?Sized,
+{
+    fn reset(&mut self, view: Option<Arc<SrcView>>) {
+        self.src_view = view;
+        self.cast.notify(&0);
+    }
+
+    fn notify(&mut self, _: &()) {
+        self.cast.notify(&0);
+    }
+}