diff --git a/src/index/map_key.rs b/src/index/map_key.rs new file mode 100644 index 0000000..73cdce8 --- /dev/null +++ b/src/index/map_key.rs @@ -0,0 +1,123 @@ +pub use { + std::{ + sync::{Arc, RwLock}, + boxed::Box + }, + crate::{ + core::{ + View, + Observer, + ObserverExt, + ObserverBroadcast, + ViewPort, + InnerViewPort, + OuterViewPort + }, + index::{IndexView} + } +}; + +impl OuterViewPort> { + pub fn map_key< + DstKey: 'static, + F1: Fn(&SrcKey) -> DstKey + Send + Sync + 'static, + F2: Fn(&DstKey) -> Option + Send + Sync + 'static, + >( + &self, + f1: F1, + f2: F2 + ) -> OuterViewPort> { + let port = ViewPort::new(); + let map = MapIndexKey::new(port.inner(), f1, f2); + self.add_observer(map.clone()); + port.into_outer() + } +} + +pub struct MapIndexKey +where SrcView: IndexView + ?Sized, + F1: Fn(&SrcKey) -> DstKey + Send + Sync, + F2: Fn(&DstKey) -> Option + Send + Sync, +{ + src_view: Option>, + f1: F1, + f2: F2, + cast: Arc>>> +} + +impl MapIndexKey +where DstKey: 'static, + SrcKey: 'static, + SrcView: IndexView + ?Sized + 'static, + SrcView::Item: Default + 'static, + F1: Fn(&SrcKey) -> DstKey + Send + Sync + 'static, + F2: Fn(&DstKey) -> Option + Send + Sync + 'static, +{ + fn new( + port: InnerViewPort>, + f1: F1, + f2: F2 + ) -> Arc> { + let map = Arc::new(RwLock::new( + MapIndexKey { + src_view: None, + f1, + f2, + cast: port.get_broadcast() + } + )); + + port.set_view(Some(map.clone())); + map + } +} + +impl View for MapIndexKey +where SrcView: IndexView + ?Sized, + F1: Fn(&SrcKey) -> DstKey + Send + Sync, + F2: Fn(&DstKey) -> Option + Send + Sync, +{ + type Msg = DstKey; +} + +impl IndexView for MapIndexKey +where SrcView: IndexView + ?Sized, + SrcView::Item: Default, + F1: Fn(&SrcKey) -> DstKey + Send + Sync, + F2: Fn(&DstKey) -> Option + Send + Sync, +{ + type Item = SrcView::Item; + + fn get(&self, key: &DstKey) -> Self::Item { + if let (Some(v), Some(k)) = (self.src_view.as_ref(), (self.f2)(key)) { + v.get(&k) + } else { + Self::Item::default() + } + } + + fn area(&self) -> Option> { + Some(self.src_view.as_ref()?.area()?.iter().map(&self.f1).collect()) + } +} + +impl Observer for MapIndexKey +where SrcView: IndexView + ?Sized, + SrcView::Item: Default, + F1: Fn(&SrcKey) -> DstKey + Send + Sync, + F2: Fn(&DstKey) -> Option + Send + Sync, +{ + fn reset(&mut self, view: Option>) { + let old_area = self.area(); + self.src_view = view; + let new_area = self.area(); + + if let Some(area) = old_area { self.cast.notify_each(area); } + if let Some(area) = new_area { self.cast.notify_each(area); } + } + + fn notify(&self, msg: &SrcKey) { + self.cast.notify(&(self.f1)(msg)); + } +} +