initial commit

This commit is contained in:
Michael Sippel 2023-02-11 15:36:05 +01:00
commit 8153da2091
Signed by: senvas
GPG Key ID: F96CF119C34B64A6
39 changed files with 4339 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
Cargo.lock
/target
*~
\#*\#

15
Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
authors = ["Michael Sippel <micha@fragmental.art>"]
edition = "2018"
name = "r3vi"
version = "0.1.0"
[dependencies]
cgmath = { version = "0.18.0", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3.3"
serde_json = "*"
[dependencies.async-std]
version = "1.9.0"
features = ["unstable", "attributes"]

43
README.md Normal file
View File

@ -0,0 +1,43 @@
# r3vi
Rust Runtime for Reactive View-Projections
Using **r3vi** you can define *Projections*, i.e. transformations on *Views* that are
updated *reactively* on changes in the source-view.
These updates are performed incrementally using fine-granuar diffs.
*Views* are abstract accessor-interfaces that also define the update protocol (the diff).
*Observers* can register to observe a *View* and are notified with the according diff-message
whenever the view changes.
*Projections* are transformations from one view into antoher.
They are made of the target view and an observer that observes the source view.
R3vi provides basic data-structures and projections to build projectional pipelines
with an interface similar to native rust iterators.
## Examples
```rust
use r3vi::buffer::vec::*;
let mut buffer = VecBuffer::<i32>::new();
buffer.push(3);
let projected_port = buffer.get_port()
.to_sequence() // make SequenceView from Vec
.map(|x| x + 10)
.filter(|x| x > 10);
let projected_view = projected_port.get_view();
assert_eq!(projected_view.get(&0), Some(13));
buffer.push(5); // maps to 15
buffer.push(-9); // maps to 1, is eliminated by filter
buffer.push(1); // maps to 11
assert_eq!(projected_view.get(&1), Some(15));
assert_eq!(projected_view.get(&2), Some(11));
```

View File

@ -0,0 +1,90 @@
use {
std::{
sync::Arc,
collections::HashMap,
hash::Hash
},
std::sync::RwLock,
crate::{
core::{
Observer,
ObserverBroadcast,
View,
InnerViewPort
},
index::{IndexArea, IndexView}
}
};
struct GridBuffer<Item> {
data: HashMap<Point2<i16>, Item>,
limit: Point2<i16>
}
impl<Item> View for GridBuffer<Item>
where Item: Clone + Send + Sync + 'static
{
type Msg = IndexArea<Point2<i16>>;
}
impl<Item> IndexView<Point2<i16>> for GridBufferView<Item>
where Item: Clone + Send + Sync + 'static
{
type Item = Item;
fn get(&self, key: &Point2<i16>) -> Option<Self::Item> {
self.data.get(key).cloned()
}
fn area(&self) -> IndexArea<Point2<i16>> {
IndexArea::Range(
Point2::new(0, 0)
..= self.limit
)
}
}
pub struct GridBufferController<Item>
where Item: Clone + Send + Sync + 'static
{
data: Arc<RwLock<HashMap<Point2<i16>, Item>>>,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<Point2<i16>, Item = Item>>>>
}
impl<Key, Item> GridBuffer<Key, Item>
where Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static
{
pub fn new(port: InnerViewPort<dyn IndexView<Point2<i16>, Item = Item>>) -> Self {
let data = Arc::new(RwLock::new(HashMap::<Point2<i16>, Item>::new()));
port.set_view(Some(Arc::new(GridBufferView(data.clone()))));
GridBuffer {
data,
cast: port.get_broadcast()
}
}
pub fn insert(&mut self, key: Point2<i16>, item: Item) {
self.data.write().unwrap().insert(key.clone(), item);
if
self.cast.notify(&IndexArea::Set(vec![ key ]));
}
pub fn insert_iter<T>(&mut self, iter: T)
where T: IntoIterator<Item = (Point2<i16>, Item)> {
for (key, item) in iter {
self.insert(key, item);
}
}
pub fn remove(&mut self, key: Point2<i16>) {
self.data.write().unwrap().remove(&key);
self.cast.notify(&IndexArea::Set(vec![ key ]));
}
}

158
src/buffer/index_hashmap.rs Normal file
View File

@ -0,0 +1,158 @@
use {
crate::{
view::{
InnerViewPort, OuterViewPort, ViewPort, View,
index::{IndexArea, IndexView},
},
},
std::sync::RwLock,
std::{collections::HashMap, hash::Hash, sync::Arc, ops::{Deref, DerefMut}},
};
pub struct IndexBufferView<Key, Item>(Arc<RwLock<HashMap<Key, Item>>>)
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static;
impl<Key, Item> View for IndexBufferView<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
type Msg = IndexArea<Key>;
}
impl<Key, Item> IndexView<Key> for IndexBufferView<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
type Item = Item;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.0.read().unwrap().get(key).cloned()
}
fn area(&self) -> IndexArea<Key> {
IndexArea::Set(self.0.read().unwrap().keys().cloned().collect())
}
}
#[derive(Clone)]
pub struct IndexBuffer<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
data: Arc<RwLock<HashMap<Key, Item>>>,
port: InnerViewPort<dyn IndexView<Key, Item = Item>>,
}
impl<Key, Item> IndexBuffer<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
pub fn with_port(port: InnerViewPort<dyn IndexView<Key, Item = Item>>) -> Self {
let data = Arc::new(RwLock::new(HashMap::<Key, Item>::new()));
port.set_view(Some(Arc::new(IndexBufferView(data.clone()))));
IndexBuffer {
data,
port
}
}
pub fn new() -> Self {
IndexBuffer::with_port(ViewPort::new().into_inner())
}
pub fn get_port(&self) -> OuterViewPort<dyn IndexView<Key, Item = Item>> {
self.port.0.outer()
}
pub fn get(&self, key: &Key) -> Option<Item> {
self.data.read().unwrap().get(key).cloned()
}
pub fn get_mut(&mut self, key: &Key) -> MutableIndexAccess<Key, Item> {
MutableIndexAccess {
buf: self.clone(),
key: key.clone(),
val: self.get(key)
}
}
pub fn update(&mut self, key: Key, item: Option<Item>) {
if let Some(item) = item {
self.data.write().unwrap().insert(key.clone(), item);
} else {
self.data.write().unwrap().remove(&key);
}
self.port.notify(&IndexArea::Set(vec![key]));
}
pub fn insert(&mut self, key: Key, item: Item) {
self.data.write().unwrap().insert(key.clone(), item);
self.port.notify(&IndexArea::Set(vec![key]));
}
pub fn insert_iter<T>(&mut self, iter: T)
where
T: IntoIterator<Item = (Key, Item)>,
{
for (key, item) in iter {
self.insert(key, item);
}
}
pub fn remove(&mut self, key: Key) {
self.data.write().unwrap().remove(&key);
self.port.notify(&IndexArea::Set(vec![key]));
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct MutableIndexAccess<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
buf: IndexBuffer<Key, Item>,
key: Key,
val: Option<Item>,
}
impl<Key, Item> Deref for MutableIndexAccess<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
type Target = Option<Item>;
fn deref(&self) -> &Option<Item> {
&self.val
}
}
impl<Key, Item> DerefMut for MutableIndexAccess<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.val
}
}
impl<Key, Item> Drop for MutableIndexAccess<Key, Item>
where
Key: Clone + Hash + Eq + Send + Sync + 'static,
Item: Clone + Send + Sync + 'static,
{
fn drop(&mut self) {
self.buf.update(self.key.clone(), self.val.clone());
}
}

5
src/buffer/mod.rs Normal file
View File

@ -0,0 +1,5 @@
pub mod singleton;
pub mod vec;
pub mod index_hashmap;

147
src/buffer/singleton.rs Normal file
View File

@ -0,0 +1,147 @@
use {
crate::{
view::{
InnerViewPort, OuterViewPort, View, ViewPort,
singleton::SingletonView
},
},
std::sync::RwLock,
std::{
ops::{Deref, DerefMut},
sync::Arc,
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct SingletonBufferView<T: Clone + Send + Sync + 'static>(Arc<RwLock<T>>);
impl<T> View for SingletonBufferView<T>
where
T: Clone + Send + Sync + 'static,
{
type Msg = ();
}
impl<T> SingletonView for SingletonBufferView<T>
where
T: Clone + Send + Sync + 'static,
{
type Item = T;
fn get(&self) -> Self::Item {
self.0.read().unwrap().clone()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct SingletonBuffer<T>
where
T: Clone + Send + Sync + 'static,
{
value: Arc<RwLock<T>>,
port: InnerViewPort<dyn SingletonView<Item = T>>
}
impl<T> SingletonBuffer<T>
where
T: Clone + Send + Sync + 'static,
{
pub fn with_port(value: T, port: InnerViewPort<dyn SingletonView<Item = T>>) -> Self {
let value = Arc::new(RwLock::new(value));
port.set_view(Some(Arc::new(SingletonBufferView(value.clone()))));
SingletonBuffer {
value,
port
}
}
pub fn new(value: T) -> Self {
SingletonBuffer::with_port(value, ViewPort::new().into_inner())
}
pub fn get_port(&self) -> OuterViewPort<dyn SingletonView<Item = T>> {
self.port.0.outer()
}
pub fn get(&self) -> T {
self.value.read().unwrap().clone()
}
pub fn get_mut(&self) -> MutableSingletonAccess<T> {
MutableSingletonAccess {
buf: self.clone(),
val: self.get(),
}
}
pub fn set(&mut self, new_value: T) {
let mut v = self.value.write().unwrap();
*v = new_value;
drop(v);
self.port.notify(&());
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct MutableSingletonAccess<T>
where
T: Clone + Send + Sync + 'static,
{
buf: SingletonBuffer<T>,
val: T,
}
impl<T> Deref for MutableSingletonAccess<T>
where
T: Clone + Send + Sync + 'static,
{
type Target = T;
fn deref(&self) -> &T {
&self.val
}
}
impl<T> DerefMut for MutableSingletonAccess<T>
where
T: Clone + Send + Sync + 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.val
}
}
impl<T> Drop for MutableSingletonAccess<T>
where
T: Clone + Send + Sync + 'static,
{
fn drop(&mut self) {
self.buf.set(self.val.clone());
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[cfg(test)]
mod tests {
use crate::buffer::singleton::*;
#[test]
fn singleton_buffer1() {
let buffer = SingletonBuffer::<char>::new('a');
let port = buffer.get_port();
assert_eq!(buffer.get(), 'a');
assert_eq!(port.get_view().get(), 'a');
*buffer.get_mut() = 'b';
assert_eq!(buffer.get(), 'b');
assert_eq!(port.get_view().get(), 'b');
}
}

193
src/buffer/vec.rs Normal file
View File

@ -0,0 +1,193 @@
use {
crate::{
view::{InnerViewPort, OuterViewPort, View, ViewPort},
},
std::sync::RwLock,
std::{
ops::{Deref, DerefMut},
sync::Arc,
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize)]
pub enum VecDiff<T> {
Clear,
Push(T),
Remove(usize),
Insert { idx: usize, val: T },
Update { idx: usize, val: T },
}
impl<T> View for Vec<T>
where
T: Clone + Send + Sync + 'static,
{
type Msg = VecDiff<T>;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct VecBuffer<T>
where
T: Clone + Send + Sync + 'static,
{
data: Arc<RwLock<Vec<T>>>,
port: InnerViewPort<RwLock<Vec<T>>>
}
impl<T> VecBuffer<T>
where
T: Clone + Send + Sync + 'static,
{
pub fn with_data_port(data: Vec<T>, port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
let data = Arc::new(RwLock::new(data));
port.set_view(Some(data.clone()));
for x in data.read().unwrap().iter().cloned() {
port.notify(&VecDiff::Push(x));
}
VecBuffer {
data,
port
}
}
pub fn with_data(data: Vec<T>) -> Self {
VecBuffer::with_data_port(data, ViewPort::new().into_inner())
}
pub fn with_port(port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
VecBuffer::with_data_port(vec![], port)
}
pub fn new() -> Self {
VecBuffer::with_port(ViewPort::new().into_inner())
}
pub fn get_port(&self) -> OuterViewPort<RwLock<Vec<T>>> {
self.port.0.outer()
}
pub fn apply_diff(&mut self, diff: VecDiff<T>) {
let mut data = self.data.write().unwrap();
match &diff {
VecDiff::Clear => {
data.clear();
}
VecDiff::Push(val) => {
data.push(val.clone());
}
VecDiff::Remove(idx) => {
data.remove(*idx);
}
VecDiff::Insert { idx, val } => {
data.insert(*idx, val.clone());
}
VecDiff::Update { idx, val } => {
data[*idx] = val.clone();
}
}
drop(data);
self.port.notify(&diff);
}
pub fn len(&self) -> usize {
self.data.read().unwrap().len()
}
pub fn get(&self, idx: usize) -> T {
self.data.read().unwrap()[idx].clone()
}
pub fn clear(&mut self) {
self.apply_diff(VecDiff::Clear);
}
pub fn push(&mut self, val: T) {
self.apply_diff(VecDiff::Push(val));
}
pub fn remove(&mut self, idx: usize) {
self.apply_diff(VecDiff::Remove(idx));
}
pub fn insert(&mut self, idx: usize, val: T) {
self.apply_diff(VecDiff::Insert { idx, val });
}
pub fn update(&mut self, idx: usize, val: T) {
self.apply_diff(VecDiff::Update { idx, val });
}
pub fn get_mut(&mut self, idx: usize) -> MutableVecAccess<T> {
MutableVecAccess {
buf: self.clone(),
idx,
val: self.get(idx),
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct MutableVecAccess<T>
where
T: Clone + Send + Sync + 'static,
{
buf: VecBuffer<T>,
idx: usize,
val: T,
}
impl<T> Deref for MutableVecAccess<T>
where
T: Clone + Send + Sync + 'static,
{
type Target = T;
fn deref(&self) -> &T {
&self.val
}
}
impl<T> DerefMut for MutableVecAccess<T>
where
T: Clone + Send + Sync + 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.val
}
}
impl<T> Drop for MutableVecAccess<T>
where
T: Clone + Send + Sync + 'static,
{
fn drop(&mut self) {
self.buf.update(self.idx, self.val.clone());
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[cfg(test)]
mod tests {
use crate::buffer::vec::*;
#[test]
fn vec_buffer1() {
let mut buffer = VecBuffer::new();
buffer.push('a');
buffer.push('b');
buffer.push('c');
}
}

48
src/lib.rs Normal file
View File

@ -0,0 +1,48 @@
#![feature(trait_alias)]
//! Rust Runtime for Reactive View-Projections
//!
//! Using **r3vi** you can define *Projections*, i.e. transformations on *Views* that are
//! updated *reactively* on changes in the source-view.
//! These updates are performed incrementally using fine-granuar diffs.
//!
//! *Views* are abstract accessor-interfaces that also define the update protocol (the diff).
//! *Observers* can register to observe a *View* and are notified with the according diff-message
//! whenever the view changes.
//! *Projections* are transformations from one view into antoher.
//! They are made of the target view and an observer that observes the source view.
//!
//! R3vi provides basic data-structures and projections to build projectional pipelines
//! with an interface similar to native rust iterators.
//!
//!
//!# Examples
//!
//! ```
//! use r3vi::buffer::vec::*;
//!
//! let mut buffer = VecBuffer::<i32>::new();
//! buffer.push(3);
//!
//! let projected_port = buffer.get_port()
//! .to_sequence() // make SequenceView from Vec
//! .map(|x| x + 10)
//! .filter(|x| x > 10);
//!
//! let projected_view = projected_port.get_view();
//!
//! assert_eq!(projected_view.get(&0), Some(13));
//!
//! buffer.push(5); // maps to 15
//! buffer.push(-9); // maps to 1, is eliminated by filter
//! buffer.push(1); // maps to 11
//!
//! assert_eq!(projected_view.get(&1), Some(15));
//! assert_eq!(projected_view.get(&2), Some(11));
//!
//! ```
pub mod view;
pub mod buffer;
pub mod projection;

View File

@ -0,0 +1,171 @@
use {
crate::{
view::{
View, OuterViewPort, Observer, ViewPort, ObserverBroadcast,
sequence::*
},
projection::projection_helper::ProjectionHelper,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
// Wrap
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct Wrapped<T>
where T: Send + Sync + 'static
{
pub(super) opening: T,
pub(super) closing: T,
pub(super) items: Arc<dyn SequenceView<Item = T>>,
pub(super) cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = T>>>>,
pub(super) proj_helper: ProjectionHelper<(), Self>,
}
impl<T> View for Wrapped<T>
where T: Clone + Send + Sync + 'static
{
type Msg = usize;
}
impl<T> SequenceView for Wrapped<T>
where T: Clone + Send + Sync + 'static
{
type Item = T;
fn len(&self) -> Option<usize> {
Some(self.items.len()? + 2)
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
let l = self.items.len().unwrap_or((-2 as i32) as usize);
if *idx < l+2 {
Some(
if *idx == 0 {
self.opening.clone()
} else if *idx < l+1 {
self.items.get(&(*idx - 1))?
} else {
self.closing.clone()
})
} else {
None
}
}
}
pub trait Wrap<T> {
fn wrap(&self, opening: T, closing: T) -> OuterViewPort<dyn SequenceView<Item = T>>;
}
impl<T> Wrap<T> for OuterViewPort<dyn SequenceView<Item = T>>
where T: Clone + Send + Sync + 'static
{
fn wrap(&self, opening: T, closing: T) -> OuterViewPort<dyn SequenceView<Item = T>> {
let port = ViewPort::new();
let mut proj_helper = ProjectionHelper::new(port.update_hooks.clone());
let w = Arc::new(RwLock::new(Wrapped {
opening,
closing,
items: proj_helper.new_sequence_arg((), self.clone(), |s: &mut Wrapped<T>, item_idx| {
s.cast.notify(&(*item_idx + 1));
s.cast.notify(&(*item_idx + 2));
}),
cast: port.get_cast(),
proj_helper,
}));
w.write().unwrap().proj_helper.set_proj(&w);
port.set_view(Some(w.clone()));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
// Separate
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct Separated<T>
where T: Send + Sync + 'static
{
pub(super) delimiter: T,
pub(super) items: Arc<dyn SequenceView<Item = T>>,
pub(super) cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = T>>>>,
pub(super) proj_helper: ProjectionHelper<(), Self>,
}
impl<T> View for Separated<T>
where T: Clone + Send + Sync + 'static
{
type Msg = usize;
}
impl<T> SequenceView for Separated<T>
where T: Clone + Send + Sync + 'static
{
type Item = T;
fn len(&self) -> Option<usize> {
let l = self.items.len()?;
if l == 0 {
Some(0)
} else if l == 1 {
Some(1)
} else {
Some(l*2 - 1)
}
}
fn get(&self, idx: &usize) -> Option<T> {
let l = self.items.len().unwrap_or(usize::MAX);
if *idx+1 < l*2 {
if *idx % 2 == 0 {
self.items.get(&(*idx / 2))
} else {
Some(self.delimiter.clone())
}
} else {
None
}
}
}
pub trait Separate<T> {
fn separate(&self, delimiter: T) -> OuterViewPort<dyn SequenceView<Item = T>>;
}
impl<T> Separate<T> for OuterViewPort<dyn SequenceView<Item = T>>
where T: Clone + Send + Sync + 'static
{
fn separate(&self, delimiter: T) -> OuterViewPort<dyn SequenceView<Item = T>> {
let port = ViewPort::new();
let mut proj_helper = ProjectionHelper::new(port.update_hooks.clone());
let w = Arc::new(RwLock::new(Separated {
delimiter,
items: proj_helper.new_sequence_arg(
(),
self.clone(),
|s: &mut Separated<T>, item_idx| {
s.cast.notify(&(*item_idx * 2));
if *item_idx > 0 {
s.cast.notify(&(*item_idx * 2 - 1));
}
}),
cast: port.get_cast(),
proj_helper,
}));
w.write().unwrap().proj_helper.set_proj(&w);
port.set_view(Some(w.clone()));
port.into_outer()
}
}

View File

@ -0,0 +1,119 @@
use {
crate::{
view::{
Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
sequence::SequenceView,
}
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
pub fn enumerate(&self) -> OuterViewPort<dyn SequenceView<Item = (usize, Item)>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let view = Arc::new(RwLock::new(EnumerateSequence {
src_view: None,
cast: port.inner().get_broadcast(),
}));
self.add_observer(view.clone());
port.inner().set_view(Some(view));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct EnumerateSequence<SrcView>
where
SrcView: SequenceView + ?Sized,
{
src_view: Option<Arc<SrcView>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = (usize, SrcView::Item)>>>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> View for EnumerateSequence<SrcView>
where
SrcView: SequenceView + ?Sized,
{
type Msg = usize;
}
impl<SrcView> SequenceView for EnumerateSequence<SrcView>
where
SrcView: SequenceView + ?Sized
{
type Item = (usize, SrcView::Item);
fn len(&self) -> Option<usize> {
self.src_view.len()
}
fn get(&self, idx: &usize) -> Option<(usize, SrcView::Item)> {
self.src_view.get(idx).map(|item| (*idx, item))
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> Observer<SrcView> for EnumerateSequence<SrcView>
where
SrcView: SequenceView + ?Sized
{
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(&mut self, msg: &usize) {
self.cast.notify(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[cfg(test)]
mod tests {
use crate::buffer::vec::*;
use crate::projection::enumerate_sequence::*;
use crate::view::port::UpdateTask;
#[test]
fn map_seq1() {
let mut buffer = VecBuffer::new();
let target_port = buffer.get_port().to_sequence().enumerate();
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((0, 0)));
assert_eq!(target_view.get(&1), Some((1, 7)));
assert_eq!(target_view.get(&2), Some((2, 9)));
assert_eq!(target_view.get(&3), None);
}
}

View File

@ -0,0 +1,25 @@
use {
crate::{
view::{
OuterViewPort,
sequence::SequenceView,
},
}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
pub fn filter_map<
DstItem: Clone + 'static,
F: Fn(&Item) -> Option<DstItem> + Send + Sync + 'static,
>(
&self,
f: F,
) -> OuterViewPort<dyn SequenceView<Item = DstItem>> {
self.map(f)
.filter(|x| x.is_some())
.map(|x| x.clone().unwrap())
}
}

View File

@ -0,0 +1,213 @@
use {
crate::{
view::{
Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
sequence::SequenceView,
},
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: SequenceView + ?Sized + 'static> OuterViewPort<V> {
pub fn filter<P: Fn(&V::Item) -> bool + Send + Sync + 'static>(
&self,
pred: P,
) -> OuterViewPort<dyn SequenceView<Item = V::Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let filter = Arc::new(RwLock::new(Filter {
src_view: None,
pred,
old_preds: RwLock::new(Vec::new()),
cast: port.inner().get_broadcast(),
}));
self.add_observer(filter.clone());
port.inner().set_view(Some(filter));
port.into_outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
struct Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
src_view: Option<Arc<SrcView>>,
pred: P,
old_preds: RwLock<Vec<bool>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = SrcView::Item>>>>,
}
impl<SrcView, P> Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
fn get_offset(&self, idx: usize) -> usize {
if let Some(v) = self.src_view.clone() {
let mut i = 0;
let mut j = 0;
let mut offset = 0;
while let (Some(x), true) = (v.get(&i), j <= idx) {
if (self.pred)(&x) {
j += 1;
} else {
offset += 1;
}
i += 1;
}
offset
} else {
0
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView, P> View for Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
type Msg = usize;
}
impl<SrcView, P> SequenceView for Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
type Item = SrcView::Item;
fn len(&self) -> Option<usize> {
if let Some(src_len) = self.src_view.len() {
Some(src_len - self.get_offset(src_len))
} else {
None
}
}
fn get(&self, idx: &usize) -> Option<Self::Item> {
self.src_view.get(&(idx + self.get_offset(*idx)))
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView, P> Observer<SrcView> for Filter<SrcView, P>
where
SrcView: SequenceView + ?Sized + 'static,
P: Fn(&SrcView::Item) -> bool + Send + Sync + 'static,
{
fn reset(&mut self, new_src: Option<Arc<SrcView>>) {
let old_len = self.len();
self.src_view = new_src;
self.old_preds = RwLock::new(Vec::new());
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(&mut self, idx: &usize) {
let l = self.len().unwrap_or(0) + 1;
let np = if let Some(x) = self.src_view.get(idx) {
(self.pred)(&x)
} else {
false
};
let mut opds = self.old_preds.write().unwrap();
opds.resize_with(1 + *idx, || false);
let op = opds.get(*idx).cloned().unwrap_or(false);
*opds.get_mut(*idx).unwrap() = np;
drop(opds);
let i = (0..*idx)
.map(|j| {
if let Some(x) = self.src_view.get(&j) {
if (self.pred)(&x) {
1
} else {
0
}
} else {
0
}
})
.sum();
if np != op {
self.cast.notify_each(i..l);
} else {
self.cast.notify(&i);
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[cfg(test)]
mod tests {
use crate::buffer::vec::*;
use crate::projection::filter_sequence::*;
use crate::view::port::UpdateTask;
#[test]
fn filter_seq1() {
let mut buffer = VecBuffer::new();
let target_port = buffer.get_port()
.to_sequence()
.filter(
|x| *x > 10
);
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(0));
assert_eq!(target_view.get(&0), None);
buffer.push(11);
target_port.0.update();
assert_eq!(target_view.len(), Some(1));
assert_eq!(target_view.get(&0), Some(11));
assert_eq!(target_view.get(&1), None);
buffer.push(13);
buffer.push(1);
buffer.push(5);
buffer.push(19);
target_port.0.update();
assert_eq!(target_view.len(), Some(3));
assert_eq!(target_view.get(&0), Some(11));
assert_eq!(target_view.get(&1), Some(13));
assert_eq!(target_view.get(&2), Some(19));
}
}

View File

@ -0,0 +1,246 @@
use {
crate::{
view::{
InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort,
grid::*,
index::*,
},
projection::projection_helper::ProjectionHelper,
},
cgmath::{Point2, Vector2},
std::sync::RwLock,
std::{cmp::max, collections::HashMap, sync::Arc},
};
impl<Item> OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>
where
Item: 'static,
{
pub fn flatten(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
Flatten::new(self.clone(), port.inner());
port.into_outer()
}
}
pub struct Chunk<Item>
where
Item: 'static,
{
offset: Vector2<i16>,
limit: Point2<i16>,
view: Arc<dyn GridView<Item = Item>>,
}
pub struct Flatten<Item>
where
Item: 'static,
{
limit: Point2<i16>,
top: Arc<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>,
chunks: HashMap<Point2<i16>, Chunk<Item>>,
cast: Arc<RwLock<ObserverBroadcast<dyn GridView<Item = Item>>>>,
proj_helper: ProjectionHelper<Point2<i16>, Self>,
}
impl<Item> View for Flatten<Item>
where
Item: 'static,
{
type Msg = IndexArea<Point2<i16>>;
}
impl<Item> IndexView<Point2<i16>> for Flatten<Item>
where
Item: 'static,
{
type Item = Item;
fn get(&self, idx: &Point2<i16>) -> Option<Self::Item> {
let chunk_idx = self.get_chunk_idx(*idx)?;
let chunk = self.chunks.get(&chunk_idx)?;
chunk.view.get(&(*idx - chunk.offset))
}
fn area(&self) -> IndexArea<Point2<i16>> {
IndexArea::Range(Point2::new(0, 0)..=self.limit)
}
}
/* TODO: remove unused projection args (bot-views) if they get replaced by a new viewport */
impl<Item> Flatten<Item>
where
Item: 'static,
{
pub fn new(
top_port: OuterViewPort<dyn GridView<Item = OuterViewPort<dyn GridView<Item = Item>>>>,
out_port: InnerViewPort<dyn GridView<Item = Item>>,
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let flat = Arc::new(RwLock::new(Flatten {
limit: Point2::new(0, 0),
top: proj_helper.new_index_arg(
Point2::new(-1, -1),
top_port,
|s: &mut Self, chunk_area| {
for chunk_idx in chunk_area.iter() {
s.update_chunk(chunk_idx);
}
},
),
chunks: HashMap::new(),
cast: out_port.get_broadcast(),
proj_helper,
}));
flat.write().unwrap().proj_helper.set_proj(&flat);
out_port.set_view(Some(flat.clone()));
flat
}
/// the top-sequence has changed the item at chunk_idx,
/// create a new observer for the contained sub sequence
fn update_chunk(&mut self, chunk_idx: Point2<i16>) {
if let Some(chunk_port) = self.top.get(&chunk_idx) {
let view = self.proj_helper.new_index_arg(
chunk_idx,
chunk_port.clone(),
move |s: &mut Self, area| {
if let Some(chunk) = s.chunks.get(&chunk_idx) {
if chunk.limit != *chunk.view.area().range().end() {
s.update_all_offsets();
}
}
if let Some(chunk) = s.chunks.get(&chunk_idx) {
s.cast.notify(&area.map(|pt| pt + chunk.offset));
}
},
);
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
chunk.view = view;
let old_limit = chunk.limit;
let new_limit = *chunk.view.area().range().end();
self.cast.notify(
&IndexArea::Range(
Point2::new(chunk.offset.x, chunk.offset.y) ..= Point2::new(chunk.offset.x + max(old_limit.x, new_limit.x), chunk.offset.y + max(old_limit.y, new_limit.y) )));
} else {
self.chunks.insert(
chunk_idx,
Chunk {
offset: Vector2::new(-1, -1),
limit: Point2::new(-1, -1),
view,
},
);
}
self.update_all_offsets();
} else {
self.proj_helper.remove_arg(&chunk_idx);
if let Some(_chunk) = self.chunks.remove(&chunk_idx) {
self.update_all_offsets();
}
}
}
/// recalculate all chunk offsets
/// and update size of flattened grid
fn update_all_offsets(&mut self) {
let top_range = self.top.area().range();
let mut col_widths = vec![0 as i16; (top_range.end().x + 1) as usize];
let mut row_heights = vec![0 as i16; (top_range.end().y + 1) as usize];
for chunk_idx in GridWindowIterator::from(top_range.clone()) {
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
let chunk_range = chunk.view.area().range();
let lim = *chunk_range.end();
col_widths[chunk_idx.x as usize] = max(
col_widths[chunk_idx.x as usize],
if lim.x < 0 { 0 } else { lim.x + 1 },
);
row_heights[chunk_idx.y as usize] = max(
row_heights[chunk_idx.y as usize],
if lim.y < 0 { 0 } else { lim.y + 1 },
);
}
}
for chunk_idx in GridWindowIterator::from(top_range.clone()) {
if let Some(chunk) = self.chunks.get_mut(&chunk_idx) {
let _old_offset = chunk.offset;
let _old_limit = chunk.limit;
//chunk.limit = Point2::new( col_widths[chunk_idx.x as usize]-1, row_heights[chunk_idx.y as usize]-1 );
chunk.limit = *chunk.view.area().range().end();
chunk.offset = Vector2::new(
(0..chunk_idx.x as usize).map(|x| col_widths[x]).sum(),
(0..chunk_idx.y as usize).map(|y| row_heights[y]).sum(),
);
/*
if old_offset != chunk.offset {
self.cast.notify(
&IndexArea::Range(
Point2::new(
std::cmp::min(old_offset.x, chunk.offset.x),
std::cmp::min(old_offset.y, chunk.offset.y)
)
..= Point2::new(
std::cmp::max(old_offset.x + old_limit.x, chunk.offset.x + chunk.limit.x),
std::cmp::max(old_offset.y + old_limit.y, chunk.offset.y + chunk.limit.y)
)
)
);
}
*/
}
}
let old_limit = self.limit;
self.limit = Point2::new(
(0..=top_range.end().x)
.map(|x| col_widths.get(x as usize).unwrap_or(&0))
.sum::<i16>()
- 1,
(0..=top_range.end().y)
.map(|y| row_heights.get(y as usize).unwrap_or(&0))
.sum::<i16>()
- 1,
);
self.cast.notify(&IndexArea::Range(
Point2::new(0, 0)
..=Point2::new(
max(self.limit.x, old_limit.x),
max(self.limit.y, old_limit.y),
),
));
}
/// given an index in the flattened sequence,
/// which sub-sequence does it belong to?
fn get_chunk_idx(&self, glob_pos: Point2<i16>) -> Option<Point2<i16>> {
for chunk_idx in GridWindowIterator::from(self.top.area().range()) {
if let Some(chunk) = self.chunks.get(&chunk_idx) {
let end = chunk.limit + chunk.offset;
if glob_pos.x <= end.x && glob_pos.y <= end.y {
return Some(chunk_idx);
}
}
}
None
}
}

View File

@ -0,0 +1,227 @@
use {
crate::{
view::{
port::UpdateTask, InnerViewPort, Observer, ObserverBroadcast, ObserverExt,
OuterViewPort, View, ViewPort,
sequence::SequenceView,
},
projection::projection_helper::ProjectionHelper,
},
std::sync::RwLock,
std::{collections::BTreeMap, sync::Arc},
};
impl<Item> OuterViewPort<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>
where
Item: 'static,
{
pub fn flatten(&self) -> OuterViewPort<dyn SequenceView<Item = Item>> {
let port = ViewPort::new();
Flatten::new(self.clone(), port.inner());
port.into_outer()
}
}
pub struct Chunk<Item>
where
Item: 'static,
{
offset: usize,
len: usize,
view: Arc<dyn SequenceView<Item = Item>>,
}
pub struct Flatten<Item>
where
Item: 'static,
{
length: usize,
top: Arc<dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>>,
chunks: BTreeMap<usize, Chunk<Item>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = Item>>>>,
proj_helper: ProjectionHelper<usize, Self>,
}
impl<Item> View for Flatten<Item>
where
Item: 'static,
{
type Msg = usize;
}
impl<Item> SequenceView for Flatten<Item>
where
Item: 'static,
{
type Item = Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
let chunk = self.chunks.get(&self.get_chunk_idx(*idx)?)?;
chunk.view.get(&(*idx - chunk.offset))
}
fn len(&self) -> Option<usize> {
Some(self.length)
}
}
impl<Item> Flatten<Item>
where
Item: 'static,
{
pub fn new(
top_port: OuterViewPort<
dyn SequenceView<Item = OuterViewPort<dyn SequenceView<Item = Item>>>,
>,
out_port: InnerViewPort<dyn SequenceView<Item = Item>>,
) -> Arc<RwLock<Self>> {
let mut proj_helper = ProjectionHelper::new(out_port.0.update_hooks.clone());
let flat = Arc::new(RwLock::new(Flatten {
length: 0,
top: proj_helper.new_sequence_arg(usize::MAX, top_port, |s: &mut Self, chunk_idx| {
s.update_chunk(*chunk_idx);
}),
chunks: BTreeMap::new(),
cast: out_port.get_broadcast(),
proj_helper,
}));
flat.write().unwrap().proj_helper.set_proj(&flat);
out_port.set_view(Some(flat.clone()));
flat
}
/// the top-sequence has changed the item at chunk_idx,
/// create a new observer for the contained sub sequence
fn update_chunk(&mut self, chunk_idx: usize) {
if let Some(chunk_port) = self.top.get(&chunk_idx) {
self.chunks.insert(
chunk_idx,
Chunk {
offset: 0, // will be adjusted by update_offsets() later
len: 0,
view: self.proj_helper.new_sequence_arg(
chunk_idx,
chunk_port.clone(),
move |s: &mut Self, idx| {
if let Some(chunk) = s.chunks.get(&chunk_idx) {
let chunk_offset = chunk.offset;
let chunk_len = chunk.view.len().unwrap_or(0);
let mut dirty_idx = Vec::new();
if chunk.len != chunk_len {
dirty_idx = s.update_all_offsets();
}
s.cast.notify(&(idx + chunk_offset));
s.cast.notify_each(dirty_idx);
} else {
let dirty_idx = s.update_all_offsets();
s.cast.notify_each(dirty_idx);
}
},
),
},
);
chunk_port.0.update();
let dirty_idx = self.update_all_offsets();
self.cast.notify_each(dirty_idx);
} else {
// todo:
self.proj_helper.remove_arg(&chunk_idx);
self.chunks.remove(&chunk_idx);
let dirty_idx = self.update_all_offsets();
self.cast.notify_each(dirty_idx);
}
}
/// recalculate all chunk offsets beginning at start_idx
/// and update length of flattened sequence
fn update_all_offsets(&mut self) -> Vec<usize> {
let mut dirty_idx = Vec::new();
let mut cur_offset = 0;
for (_chunk_idx, chunk) in self.chunks.iter_mut() {
let old_offset = chunk.offset;
chunk.offset = cur_offset;
chunk.len = chunk.view.len().unwrap_or(0);
if old_offset != cur_offset {
dirty_idx.extend(
std::cmp::min(old_offset, cur_offset)
..std::cmp::max(old_offset, cur_offset) + chunk.len,
);
}
cur_offset += chunk.len;
}
let old_length = self.length;
self.length = cur_offset;
dirty_idx.extend(self.length..old_length);
dirty_idx
}
/// given an index in the flattened sequence,
/// which sub-sequence does it belong to?
fn get_chunk_idx(&self, glob_idx: usize) -> Option<usize> {
let mut offset = 0;
for (chunk_idx, chunk) in self.chunks.iter() {
offset += chunk.view.len().unwrap_or(0);
if glob_idx < offset {
return Some(*chunk_idx);
}
}
None
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[cfg(test)]
mod tests {
use crate::buffer::vec::*;
use crate::projection::flatten_sequence::*;
use crate::view::port::UpdateTask;
#[test]
fn flatten1() {
let mut buffer = VecBuffer::new();
let target_port = buffer.get_port().to_sequence().flatten();
let target_view = target_port.get_view();
let b1 = VecBuffer::with_data(
vec!['h', 'a', 'l', 'l', 'o']
);
let b2 = VecBuffer::with_data(
vec!['w', 'e', 'l', 't']
);
let b3 = VecBuffer::with_data(
vec!['!']
);
buffer.push( b1.get_port().to_sequence() );
buffer.push( b2.get_port().to_sequence() );
buffer.push( b3.get_port().to_sequence() );
target_port.0.update();
assert_eq!(target_view.len(), Some(10));
assert_eq!(target_view.get(&0), Some('h'));
assert_eq!(target_view.get(&5), Some('w'));
assert_eq!(target_view.get(&6), Some('e'));
assert_eq!(target_view.get(&9), Some('!'));
assert_eq!(target_view.get(&10), None);
}
}

View File

@ -0,0 +1,88 @@
use {
crate::{
view::{
InnerViewPort, Observer, ObserverBroadcast,
OuterViewPort, View, ViewPort,
singleton::SingletonView,
},
projection::projection_helper::ProjectionHelper,
},
std::sync::RwLock,
std::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
}
}

View File

@ -0,0 +1,21 @@
use {
crate::{
view::{
OuterViewPort,
grid::GridView,
}
},
cgmath::Vector2,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item> OuterViewPort<dyn GridView<Item = Item>>
where
Item: 'static,
{
pub fn offset(&self, offset: Vector2<i16>) -> OuterViewPort<dyn GridView<Item = Item>> {
self.map_key(move |pt| pt + offset, move |pt| Some(pt - offset))
}
}

View File

@ -0,0 +1,107 @@
pub use {
crate::{
view::{
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
index::{IndexArea, IndexView},
},
},
std::sync::RwLock,
std::{boxed::Box, sync::Arc},
};
impl<Key, Item> OuterViewPort<dyn IndexView<Key, Item = Item>>
where
Key: Clone + Send + Sync + 'static,
Item: Send + Sync + 'static,
{
pub fn map_item<DstItem: 'static, F: Fn(&Key, &Item) -> DstItem + Send + Sync + 'static>(
&self,
f: F,
) -> OuterViewPort<dyn IndexView<Key, Item = DstItem>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = MapIndexItem::new(port.inner(), f);
self.add_observer(map.clone());
port.into_outer()
}
}
pub struct MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
{
src_view: Option<Arc<SrcView>>,
f: F,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<Key, Item = DstItem>>>>,
}
impl<Key, DstItem, SrcView, F> MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync + 'static,
DstItem: 'static,
SrcView: IndexView<Key> + ?Sized + 'static,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync + 'static,
{
fn new(port: InnerViewPort<dyn IndexView<Key, Item = DstItem>>, f: F) -> Arc<RwLock<Self>> {
let map = Arc::new(RwLock::new(MapIndexItem {
src_view: None,
f,
cast: port.get_broadcast(),
}));
port.set_view(Some(map.clone()));
map
}
}
impl<Key, DstItem, SrcView, F> View for MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
{
type Msg = IndexArea<Key>;
}
impl<Key, DstItem, SrcView, F> IndexView<Key> for MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
{
type Item = DstItem;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.src_view
.get(key)
.as_ref()
.map(|item| (self.f)(key, item))
}
fn area(&self) -> IndexArea<Key> {
self.src_view.area()
}
}
impl<Key, DstItem, SrcView, F> Observer<SrcView> for MapIndexItem<Key, DstItem, SrcView, F>
where
Key: Clone + Send + Sync,
SrcView: IndexView<Key> + ?Sized,
F: Fn(&Key, &SrcView::Item) -> DstItem + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area();
self.src_view = view;
self.cast.notify(&old_area);
self.cast.notify(&self.src_view.area())
}
fn notify(&mut self, area: &IndexArea<Key>) {
self.cast.notify(area);
}
}

View File

@ -0,0 +1,145 @@
pub use {
crate::{
view::{
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
grid::GridView,
index::{IndexArea, IndexView},
},
},
std::sync::RwLock,
std::{boxed::Box, sync::Arc},
};
impl<SrcKey, Item> OuterViewPort<dyn IndexView<SrcKey, Item = Item>>
where
SrcKey: Clone + Send + Sync + 'static,
Item: 'static,
{
pub fn map_key<
DstKey: Clone + Send + Sync + 'static,
F1: Fn(&SrcKey) -> DstKey + Send + Sync + 'static,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync + 'static,
>(
&self,
f1: F1,
f2: F2,
) -> OuterViewPort<dyn IndexView<DstKey, Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = MapIndexKey::new(port.inner(), f1, f2);
self.add_observer(map.clone());
port.into_outer()
}
}
impl<Item> OuterViewPort<dyn IndexView<usize, Item = Item>>
where
Item: 'static,
{
pub fn to_grid_horizontal(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.map_key(
|idx| cgmath::Point2::new(*idx as i16, 0),
|pt| if pt.y == 0 { Some(pt.x as usize) } else { None },
)
}
pub fn to_grid_vertical(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.map_key(
|idx| cgmath::Point2::new(0, *idx as i16),
|pt| if pt.x == 0 { Some(pt.y as usize) } else { None },
)
}
}
pub struct MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync,
SrcKey: Clone + Send + Sync,
SrcView: IndexView<SrcKey> + ?Sized,
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{
src_view: Option<Arc<SrcView>>,
f1: F1,
f2: F2,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<DstKey, Item = SrcView::Item>>>>,
}
impl<DstKey, SrcKey, SrcView, F1, F2> MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync + 'static,
SrcKey: Clone + Send + Sync + 'static,
SrcView: IndexView<SrcKey> + ?Sized + 'static,
SrcView::Item: 'static,
F1: Fn(&SrcKey) -> DstKey + Send + Sync + 'static,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync + 'static,
{
fn new(
port: InnerViewPort<dyn IndexView<DstKey, Item = SrcView::Item>>,
f1: F1,
f2: F2,
) -> Arc<RwLock<Self>> {
let map = Arc::new(RwLock::new(MapIndexKey {
src_view: None,
f1,
f2,
cast: port.get_broadcast(),
}));
port.set_view(Some(map.clone()));
map
}
}
impl<DstKey, SrcKey, SrcView, F1, F2> View for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync,
SrcKey: Clone + Send + Sync,
SrcView: IndexView<SrcKey> + ?Sized,
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{
type Msg = IndexArea<DstKey>;
}
impl<DstKey, SrcKey, SrcView, F1, F2> IndexView<DstKey>
for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync,
SrcKey: Clone + Send + Sync,
SrcView: IndexView<SrcKey> + ?Sized,
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{
type Item = SrcView::Item;
fn get(&self, key: &DstKey) -> Option<Self::Item> {
self.src_view.get(&(self.f2)(key)?)
}
fn area(&self) -> IndexArea<DstKey> {
self.src_view.area().map(&self.f1)
}
}
impl<DstKey, SrcKey, SrcView, F1, F2> Observer<SrcView>
for MapIndexKey<DstKey, SrcKey, SrcView, F1, F2>
where
DstKey: Clone + Send + Sync,
SrcKey: Clone + Send + Sync,
SrcView: IndexView<SrcKey> + ?Sized,
F1: Fn(&SrcKey) -> DstKey + Send + Sync,
F2: Fn(&DstKey) -> Option<SrcKey> + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area();
self.src_view = view;
self.cast.notify(&old_area);
self.cast.notify(&self.area());
}
fn notify(&mut self, msg: &IndexArea<SrcKey>) {
self.cast.notify(&msg.map(&self.f1));
}
}

View File

@ -0,0 +1,127 @@
use {
crate::{
view::{
Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
sequence::SequenceView,
},
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
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();
port.add_update_hook(Arc::new(self.0.clone()));
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(&mut self, msg: &usize) {
self.cast.notify(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[cfg(test)]
mod tests {
use crate::buffer::vec::*;
use crate::projection::map_sequence::*;
use crate::view::port::UpdateTask;
#[test]
fn map_seq1() {
let mut buffer = VecBuffer::new();
let target_port = buffer.get_port().to_sequence().map(|x| x + 10);
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(10));
assert_eq!(target_view.get(&1), Some(17));
assert_eq!(target_view.get(&2), Some(19));
assert_eq!(target_view.get(&3), None);
}
}

View File

@ -0,0 +1,109 @@
use {
crate::{
view::{
Observer, ObserverBroadcast, OuterViewPort, View, ViewPort,
singleton::SingletonView,
}
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
pub fn map<DstItem: 'static, F: Fn(Item) -> DstItem + Send + Sync + 'static>(
&self,
f: F,
) -> OuterViewPort<dyn SingletonView<Item = DstItem>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = Arc::new(RwLock::new(MapSingleton {
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 MapSingleton<DstItem, SrcView, F>
where
SrcView: SingletonView + ?Sized,
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
{
src_view: Option<Arc<SrcView>>,
f: F,
cast: Arc<RwLock<ObserverBroadcast<dyn SingletonView<Item = DstItem>>>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<DstItem, SrcView, F> View for MapSingleton<DstItem, SrcView, F>
where
SrcView: SingletonView + ?Sized,
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
{
type Msg = ();
}
impl<DstItem, SrcView, F> SingletonView for MapSingleton<DstItem, SrcView, F>
where
SrcView: SingletonView + ?Sized,
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
{
type Item = DstItem;
fn get(&self) -> DstItem {
(self.f)(self.src_view.as_ref().unwrap().get())
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<DstItem, SrcView, F> Observer<SrcView> for MapSingleton<DstItem, SrcView, F>
where
SrcView: SingletonView + ?Sized,
F: Fn(SrcView::Item) -> DstItem + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
self.src_view = view;
self.cast.notify(&());
}
fn notify(&mut self, msg: &()) {
self.cast.notify(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[cfg(test)]
mod tests {
use crate::{
buffer::singleton::*,
projection::map_singleton::*
};
#[test]
fn singleton_map1() {
let mut buffer = SingletonBuffer::new(0);
let src_port = buffer.get_port();
let dst_port = src_port.map(|x| x + 10);
let dst_view = dst_port.get_view();
assert_eq!(dst_view.get(), 10);
buffer.set(5);
assert_eq!(dst_view.get(), 15);
}
}

22
src/projection/mod.rs Normal file
View File

@ -0,0 +1,22 @@
pub mod projection_helper;
pub mod sgl2idx;
pub mod sgl2seq;
pub mod vec2seq;
pub mod vec2bin;
pub mod vec2json;
pub mod seq2idx;
pub mod enumerate_sequence;
pub mod filter_sequence;
pub mod filter_map_sequence;
pub mod flatten_singleton;
pub mod flatten_sequence;
pub mod flatten_grid;
pub mod map_singleton;
pub mod map_sequence;
pub mod map_index_item;
pub mod map_index_key;
pub mod grid_offset;
pub mod decorate_sequence;

View File

@ -0,0 +1,239 @@
use {
crate::{
view::{
channel::{queue_channel, set_channel, ChannelData, ChannelReceiver, ChannelSender},
port::UpdateTask,
Observer, ObserverExt, OuterViewPort, View,
index::{IndexArea, IndexView},
sequence::SequenceView,
singleton::SingletonView,
},
},
std::sync::RwLock,
std::{
any::Any,
cmp::max,
collections::HashMap,
hash::Hash,
sync::{Arc, Weak},
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ProjectionHelper<ArgKey, P>
where
ArgKey: Clone + Hash + Eq,
P: Send + Sync + 'static,
{
keepalive: HashMap<ArgKey, (usize, Arc<dyn Any + Send + Sync>)>,
proj: Arc<RwLock<Weak<RwLock<P>>>>,
update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
}
impl<ArgKey, P> ProjectionHelper<ArgKey, P>
where
ArgKey: Clone + Hash + Eq,
P: Send + Sync + 'static,
{
pub fn new(update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>) -> Self {
ProjectionHelper {
keepalive: HashMap::new(),
proj: Arc::new(RwLock::new(Weak::new())),
update_hooks,
}
}
pub fn set_proj(&mut self, proj: &Arc<RwLock<P>>) {
*self.proj.write().unwrap() = Arc::downgrade(proj);
}
// todo: make this functions generic over the View
// this does currently not work because Observer<V> is not implemented for ProjectionArg for *all* V.
pub fn new_singleton_arg<Item: 'static>(
&mut self,
arg_key: ArgKey,
port: OuterViewPort<dyn SingletonView<Item = Item>>,
notify: impl Fn(&mut P, &()) + Send + Sync + 'static,
) -> Arc<RwLock<Option<Arc<dyn SingletonView<Item = Item>>>>> {
port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel()));
port.get_view_arc()
}
pub fn new_sequence_arg<Item: 'static>(
&mut self,
arg_key: ArgKey,
port: OuterViewPort<dyn SequenceView<Item = Item>>,
notify: impl Fn(&mut P, &usize) + Send + Sync + 'static,
) -> Arc<RwLock<Option<Arc<dyn SequenceView<Item = Item>>>>> {
port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, set_channel()));
port.get_view_arc()
}
pub fn new_index_arg<Key: Clone + Send + Sync + 'static, Item: 'static>(
&mut self,
arg_key: ArgKey,
port: OuterViewPort<dyn IndexView<Key, Item = Item>>,
notify: impl Fn(&mut P, &IndexArea<Key>) + Send + Sync + 'static,
) -> Arc<RwLock<Option<Arc<dyn IndexView<Key, Item = Item>>>>> {
port.add_observer(self.new_arg(arg_key, Arc::new(port.0.clone()), notify, queue_channel()));
port.get_view_arc()
}
pub fn new_arg<V: View + ?Sized + 'static, D: ChannelData<Item = V::Msg> + 'static>(
&mut self,
arg_key: ArgKey,
src_update: Arc<dyn UpdateTask>,
notify: impl Fn(&mut P, &V::Msg) + Send + Sync + 'static,
(tx, rx): (ChannelSender<D>, ChannelReceiver<D>),
) -> Arc<RwLock<ProjectionArg<P, V, D>>>
where
V::Msg: Send + Sync,
D::IntoIter: Send + Sync + 'static,
{
self.remove_arg(&arg_key);
let arg = Arc::new(RwLock::new(ProjectionArg {
src: None,
notify: Box::new(notify),
proj: self.proj.clone(),
rx,
tx,
}));
let mut hooks = self.update_hooks.write().unwrap();
let idx = hooks.len();
hooks.push(src_update);
hooks.push(arg.clone());
self.keepalive.insert(arg_key, (idx, arg.clone()));
arg
}
pub fn remove_arg(&mut self, arg_key: &ArgKey) {
let mut hooks = self.update_hooks.write().unwrap();
if let Some((idx, _arg)) = self.keepalive.remove(arg_key) {
hooks.remove(idx);
hooks.remove(idx);
for (_, (j, _)) in self.keepalive.iter_mut() {
if *j > idx {
*j -= 2;
}
}
}
}
}
/// Special Observer which can access the state of the projection on notify
/// also handles the reset()
pub struct ProjectionArg<P, V, D>
where
P: Send + Sync + 'static,
V: View + ?Sized,
D: ChannelData<Item = V::Msg>,
D::IntoIter: Send + Sync,
{
src: Option<Arc<V>>,
notify: Box<dyn Fn(&mut P, &V::Msg) + Send + Sync + 'static>,
proj: Arc<RwLock<Weak<RwLock<P>>>>,
rx: ChannelReceiver<D>,
tx: ChannelSender<D>,
}
impl<P, V, D> UpdateTask for ProjectionArg<P, V, D>
where
P: Send + Sync + 'static,
V: View + ?Sized,
D: ChannelData<Item = V::Msg>,
D::IntoIter: Send + Sync,
{
fn update(&self) {
if let Some(p) = self.proj.read().unwrap().upgrade() {
if let Some(data) = self.rx.try_recv() {
for msg in data {
//eprintln!("proj update {:?}", msg);
(self.notify)(&mut *p.write().unwrap(), &msg);
}
}
} else {
//eprintln!("proj update: upgrade fail");
}
}
}
impl<P, V, D> UpdateTask for RwLock<ProjectionArg<P, V, D>>
where
P: Send + Sync + 'static,
V: View + ?Sized,
D: ChannelData<Item = V::Msg>,
D::IntoIter: Send + Sync,
{
fn update(&self) {
self.read().unwrap().update();
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<P, Item, D> Observer<dyn SingletonView<Item = Item>>
for ProjectionArg<P, dyn SingletonView<Item = Item>, D>
where
P: Send + Sync + 'static,
D: ChannelData<Item = ()>,
D::IntoIter: Send + Sync,
{
fn reset(&mut self, new_src: Option<Arc<dyn SingletonView<Item = Item>>>) {
self.src = new_src;
self.notify(&());
}
fn notify(&mut self, msg: &()) {
self.tx.send(msg.clone());
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<P, Item, D> Observer<dyn SequenceView<Item = Item>>
for ProjectionArg<P, dyn SequenceView<Item = Item>, D>
where
P: Send + Sync + 'static,
D: ChannelData<Item = usize>,
D::IntoIter: Send + Sync,
{
fn reset(&mut self, new_src: Option<Arc<dyn SequenceView<Item = Item>>>) {
let old_len = self.src.len().unwrap_or(0);
self.src = new_src;
let new_len = self.src.len().unwrap_or(0);
self.notify_each(0..max(old_len, new_len));
}
fn notify(&mut self, msg: &usize) {
self.tx.send(*msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<P, Key, Item, D> Observer<dyn IndexView<Key, Item = Item>>
for ProjectionArg<P, dyn IndexView<Key, Item = Item>, D>
where
P: Send + Sync + 'static,
Key: Clone + Send + Sync,
D: ChannelData<Item = IndexArea<Key>>,
D::IntoIter: Send + Sync,
{
fn reset(&mut self, new_src: Option<Arc<dyn IndexView<Key, Item = Item>>>) {
let old_area = self.src.area();
self.src = new_src;
self.notify(&old_area);
self.notify(&self.src.area())
}
fn notify(&mut self, msg: &IndexArea<Key>) {
self.tx.send(msg.clone());
}
}

101
src/projection/seq2idx.rs Normal file
View File

@ -0,0 +1,101 @@
use {
crate::{
view::{
InnerViewPort, Observer, ObserverBroadcast, OuterViewPort, View, ViewPort,
grid::GridView,
index::{IndexArea, IndexView},
sequence::SequenceView,
}
},
std::sync::Arc,
std::sync::RwLock,
};
/// Transforms a SequenceView into IndexView<usize>
pub struct Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
src_view: Option<Arc<SrcView>>,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<usize, Item = SrcView::Item>>>>,
}
impl<SrcView> Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
pub fn new(
port: InnerViewPort<dyn IndexView<usize, Item = SrcView::Item>>,
) -> Arc<RwLock<Self>> {
let s2i = Arc::new(RwLock::new(Sequence2Index {
src_view: None,
cast: port.get_broadcast(),
}));
port.set_view(Some(s2i.clone()));
s2i
}
}
impl<Item: 'static> OuterViewPort<dyn SequenceView<Item = Item>> {
pub fn to_index(&self) -> OuterViewPort<dyn IndexView<usize, Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
self.add_observer(Sequence2Index::new(port.inner()));
port.into_outer()
}
pub fn to_grid_horizontal(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.to_index().to_grid_horizontal()
}
pub fn to_grid_vertical(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.to_index().to_grid_vertical()
}
}
impl<SrcView> View for Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
type Msg = IndexArea<usize>;
}
impl<SrcView> IndexView<usize> for Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
type Item = SrcView::Item;
fn get(&self, key: &usize) -> Option<Self::Item> {
self.src_view.get(key)
}
fn area(&self) -> IndexArea<usize> {
if let Some(len) = self.src_view.len() {
if len > 0 {
IndexArea::Range(0..=len - 1)
} else {
IndexArea::Empty
}
} else {
IndexArea::Full
}
}
}
impl<SrcView> Observer<SrcView> for Sequence2Index<SrcView>
where
SrcView: SequenceView + ?Sized + 'static,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
let old_area = self.area();
self.src_view = view;
self.cast.notify(&old_area);
self.cast.notify(&self.area());
}
fn notify(&mut self, idx: &usize) {
self.cast.notify(&IndexArea::Set(vec![*idx]));
}
}

93
src/projection/sgl2idx.rs Normal file
View File

@ -0,0 +1,93 @@
use {
crate::{
view::{
Observer, ObserverBroadcast, OuterViewPort, View, ViewPort,
grid::GridView,
index::{IndexArea, IndexView},
singleton::SingletonView,
}
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Item: 'static> OuterViewPort<dyn SingletonView<Item = Item>> {
pub fn to_index(&self) -> OuterViewPort<dyn IndexView<(), Item = Item>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let map = Arc::new(RwLock::new(Singleton2Index {
src_view: None,
cast: port.inner().get_broadcast(),
}));
self.add_observer(map.clone());
port.inner().set_view(Some(map));
port.into_outer()
}
pub fn to_grid(&self) -> OuterViewPort<dyn GridView<Item = Item>> {
self.to_index().map_key(
|_msg: &()| cgmath::Point2::new(0, 0),
|pt| {
if pt.x == 0 && pt.y == 0 {
Some(())
} else {
None
}
},
)
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct Singleton2Index<SrcView>
where
SrcView: SingletonView + ?Sized,
{
src_view: Option<Arc<SrcView>>,
cast: Arc<RwLock<ObserverBroadcast<dyn IndexView<(), Item = SrcView::Item>>>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> View for Singleton2Index<SrcView>
where
SrcView: SingletonView + ?Sized,
{
type Msg = IndexArea<()>;
}
impl<SrcView> IndexView<()> for Singleton2Index<SrcView>
where
SrcView: SingletonView + ?Sized,
{
type Item = SrcView::Item;
fn area(&self) -> IndexArea<()> {
IndexArea::Set(vec![ () ])
}
fn get(&self, _msg: &()) -> Option<Self::Item> {
Some(self.src_view.as_ref().unwrap().get())
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<SrcView> Observer<SrcView> for Singleton2Index<SrcView>
where
SrcView: SingletonView + ?Sized,
{
fn reset(&mut self, view: Option<Arc<SrcView>>) {
self.src_view = view;
self.cast.notify(&IndexArea::Set(vec![ () ]));
}
fn notify(&mut self, _: &()) {
self.cast.notify(&IndexArea::Set(vec![ () ]));
}
}

83
src/projection/sgl2seq.rs Normal file
View File

@ -0,0 +1,83 @@
use {
crate::{
view::{
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> {
if *idx == 0 {
Some(self.src_view.as_ref()?.get())
} else {
None
}
}
fn len(&self) -> Option<usize> {
Some(if self.src_view.is_some() { 1 } else { 0 })
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
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);
}
}

85
src/projection/vec2bin.rs Normal file
View File

@ -0,0 +1,85 @@
use {
crate::{
view::{
Observer, OuterViewPort,
},
buffer::{
vec::VecDiff,
}
},
serde::Serialize,
std::sync::RwLock,
std::{io::Write, sync::Arc},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/// Serialization Observer for `Vec`
pub struct VecBinWriter<T, W>
where
T: Clone + Send + Sync + 'static,
W: Write + Send + Sync,
{
data: Option<Arc<RwLock<Vec<T>>>>,
out: RwLock<W>,
}
impl<T> OuterViewPort<RwLock<Vec<T>>>
where
T: Clone + Serialize + Send + Sync + 'static,
{
pub fn serialize_bin<W: Write + Send + Sync + 'static>(
&self,
out: W,
) -> Arc<RwLock<VecBinWriter<T, W>>> {
let writer = Arc::new(RwLock::new(VecBinWriter {
data: None,
out: RwLock::new(out),
}));
self.add_observer(writer.clone());
writer
}
}
impl<T, W> Observer<RwLock<Vec<T>>> for VecBinWriter<T, W>
where
T: Clone + Serialize + Send + Sync + 'static,
W: Write + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
self.data = view;
let mut out = self.out.write().unwrap();
out.write(
&bincode::serialized_size(&VecDiff::<T>::Clear)
.unwrap()
.to_le_bytes(),
)
.expect("");
out.write(&bincode::serialize(&VecDiff::<T>::Clear).unwrap())
.expect("");
if let Some(data) = self.data.as_ref() {
for x in data.read().unwrap().iter() {
out.write(
&bincode::serialized_size(&VecDiff::Push(x))
.unwrap()
.to_le_bytes(),
)
.expect("");
out.write(&bincode::serialize(&VecDiff::Push(x)).unwrap())
.expect("");
}
}
out.flush().expect("");
}
fn notify(&mut self, diff: &VecDiff<T>) {
let mut out = self.out.write().unwrap();
out.write(&bincode::serialized_size(diff).unwrap().to_le_bytes())
.expect("");
out.write(&bincode::serialize(diff).unwrap()).expect("");
out.flush().expect("");
}
}

110
src/projection/vec2json.rs Normal file
View File

@ -0,0 +1,110 @@
use {
crate::{
view::{Observer, OuterViewPort},
buffer::vec::{VecBuffer, VecDiff},
},
async_std::{
io::{Read, ReadExt},
stream::StreamExt,
},
serde::{de::DeserializeOwned, Serialize},
std::sync::RwLock,
std::{io::Write, sync::Arc},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct VecJsonWriter<T, W>
where
T: Clone + Send + Sync + 'static,
W: Write + Send + Sync,
{
data: Option<Arc<RwLock<Vec<T>>>>,
out: RwLock<W>,
}
impl<T> OuterViewPort<RwLock<Vec<T>>>
where
T: Clone + Serialize + Send + Sync + 'static,
{
pub fn serialize_json<W: Write + Send + Sync + 'static>(
&self,
out: W,
) -> Arc<RwLock<VecJsonWriter<T, W>>> {
let writer = Arc::new(RwLock::new(VecJsonWriter {
data: None,
out: RwLock::new(out),
}));
self.add_observer(writer.clone());
writer
}
}
impl<T, W> Observer<RwLock<Vec<T>>> for VecJsonWriter<T, W>
where
T: Clone + Serialize + Send + Sync + 'static,
W: Write + Send + Sync,
{
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
self.data = view;
self.out
.write()
.unwrap()
.write(
&serde_json::to_string(&VecDiff::<T>::Clear)
.unwrap()
.as_bytes(),
)
.expect("");
self.out.write().unwrap().write(b"\n").expect("");
if let Some(data) = self.data.as_ref() {
for x in data.read().unwrap().iter() {
self.out
.write()
.unwrap()
.write(&serde_json::to_string(&VecDiff::Push(x)).unwrap().as_bytes())
.expect("");
self.out.write().unwrap().write(b"\n").expect("");
}
}
self.out.write().unwrap().flush().expect("");
}
fn notify(&mut self, diff: &VecDiff<T>) {
self.out
.write()
.unwrap()
.write(serde_json::to_string(diff).unwrap().as_bytes())
.expect("");
self.out.write().unwrap().write(b"\n").expect("");
self.out.write().unwrap().flush().expect("");
}
}
impl<T> VecBuffer<T>
where
T: DeserializeOwned + Clone + Send + Sync + 'static,
{
pub async fn from_json<R: Read + async_std::io::Read + Unpin>(&mut self, read: R) {
let mut bytes = read.bytes();
let mut s = String::new();
while let Some(Ok(b)) = bytes.next().await {
match b {
b'\n' => {
if s.len() > 0 {
let diff =
serde_json::from_str::<VecDiff<T>>(&s).expect("error parsing json");
self.apply_diff(diff);
s.clear();
}
}
c => {
s.push(c as char);
}
}
}
}
}

118
src/projection/vec2seq.rs Normal file
View File

@ -0,0 +1,118 @@
use {
crate::{
view::{
InnerViewPort, Observer, ObserverBroadcast, ObserverExt, OuterViewPort, View, ViewPort,
sequence::SequenceView,
},
buffer::vec::VecDiff,
},
std::sync::Arc,
std::sync::RwLock,
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/// Adapter View implementing `Sequence` for `Vec`
pub struct VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
cur_len: usize,
data: Option<Arc<RwLock<Vec<T>>>>,
cast: Arc<RwLock<ObserverBroadcast<dyn SequenceView<Item = T>>>>,
}
impl<T> VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
pub fn new(port: InnerViewPort<dyn SequenceView<Item = T>>) -> Arc<RwLock<Self>> {
let seq = Arc::new(RwLock::new(VecSequence {
cur_len: 0,
data: None,
cast: port.get_broadcast(),
}));
port.set_view(Some(seq.clone()));
seq
}
}
impl<T> Observer<RwLock<Vec<T>>> for VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
fn reset(&mut self, view: Option<Arc<RwLock<Vec<T>>>>) {
let old_len = self.cur_len;
self.data = view;
let new_len = if let Some(data) = self.data.as_ref() {
data.read().unwrap().len()
} else {
0
};
self.cur_len = new_len;
self.cast.notify_each(0..std::cmp::max(old_len, new_len));
}
fn notify(&mut self, diff: &VecDiff<T>) {
match diff {
VecDiff::Clear => {
self.cast.notify_each(0..self.cur_len);
self.cur_len = 0
}
VecDiff::Push(_) => {
self.cast.notify(&self.cur_len);
self.cur_len += 1;
}
VecDiff::Remove(idx) => {
self.cast.notify_each(*idx..self.cur_len);
self.cur_len -= 1;
}
VecDiff::Insert { idx, val: _ } => {
self.cur_len += 1;
self.cast.notify_each(*idx..self.cur_len);
}
VecDiff::Update { idx, val: _ } => {
self.cast.notify(&idx);
}
}
}
}
impl<T> View for VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
type Msg = usize;
}
impl<T> SequenceView for VecSequence<T>
where
T: Clone + Send + Sync + 'static,
{
type Item = T;
fn get(&self, idx: &usize) -> Option<T> {
self.data.as_ref()?.read().unwrap().get(*idx).cloned()
}
fn len(&self) -> Option<usize> {
Some(self.cur_len)
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<T> OuterViewPort<RwLock<Vec<T>>>
where
T: Clone + Send + Sync + 'static,
{
pub fn to_sequence(&self) -> OuterViewPort<dyn SequenceView<Item = T>> {
let port = ViewPort::new();
port.add_update_hook(Arc::new(self.0.clone()));
let vec_seq = VecSequence::new(port.inner());
self.add_observer(vec_seq.clone());
port.into_outer()
}
}

222
src/view/channel.rs Normal file
View File

@ -0,0 +1,222 @@
use {
crate::view::{View, Observer},
async_std::stream::Stream,
core::{
pin::Pin,
task::{Context, Poll, Waker},
},
std::{
collections::HashSet,
hash::Hash,
sync::{Arc, Mutex},
},
};
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Traits
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub trait ChannelData: Default + IntoIterator + Send + Sync {
fn channel_insert(&mut self, x: Self::Item);
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Queue Channel
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
impl<T> ChannelData for Vec<T>
where
T: Send + Sync,
{
fn channel_insert(&mut self, x: T) {
self.push(x);
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Set Channel
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
impl<T> ChannelData for HashSet<T>
where
T: Eq + Hash + Send + Sync,
{
fn channel_insert(&mut self, x: T) {
self.insert(x);
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Singleton Channel
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
impl<T> ChannelData for Option<T>
where
T: Send + Sync,
{
fn channel_insert(&mut self, x: T) {
*self = Some(x);
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Channel
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
struct ChannelState<Data: ChannelData> {
send_buf: Option<Data>,
recv_iter: Option<Data::IntoIter>,
num_senders: usize,
waker: Option<Waker>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ChannelSender<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
pub struct ChannelReceiver<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Data: ChannelData> ChannelSender<Data>
where
Data::IntoIter: Send + Sync,
{
pub fn send(&self, msg: Data::Item) {
let mut state = self.0.lock().unwrap();
if state.send_buf.is_none() {
state.send_buf = Some(Data::default());
}
state.send_buf.as_mut().unwrap().channel_insert(msg);
if let Some(waker) = state.waker.take() {
waker.wake();
}
}
}
impl<V: View + ?Sized, Data: ChannelData<Item = V::Msg>> Observer<V> for ChannelSender<Data>
where
V::Msg: Clone,
Data::IntoIter: Send + Sync,
{
fn notify(&mut self, msg: &V::Msg) {
self.send(msg.clone());
}
}
impl<Data: ChannelData> Clone for ChannelSender<Data> {
fn clone(&self) -> Self {
self.0.lock().unwrap().num_senders += 1;
ChannelSender(self.0.clone())
}
}
impl<Data: ChannelData> Drop for ChannelSender<Data> {
fn drop(&mut self) {
let mut state = self.0.lock().unwrap();
state.num_senders -= 1;
if let Some(waker) = state.waker.take() {
waker.wake();
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Data: ChannelData> ChannelReceiver<Data> {
pub async fn recv(&self) -> Option<Data> {
ChannelRead(self.0.clone()).await
}
pub fn try_recv(&self) -> Option<Data> {
let mut state = self.0.lock().unwrap();
if let Some(buf) = state.send_buf.take() {
Some(buf)
} else {
None
}
}
}
struct ChannelRead<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
impl<Data: ChannelData> std::future::Future for ChannelRead<Data> {
type Output = Option<Data>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let mut state = self.0.lock().unwrap();
if let Some(buf) = state.send_buf.take() {
Poll::Ready(Some(buf))
} else if state.num_senders == 0 {
Poll::Ready(None)
} else {
state.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Data: ChannelData> Stream for ChannelReceiver<Data> {
type Item = Data::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut state = self.0.lock().unwrap();
if let Some(recv_iter) = state.recv_iter.as_mut() {
if let Some(val) = recv_iter.next() {
return Poll::Ready(Some(val));
} else {
state.recv_iter = None
}
}
if let Some(send_buf) = state.send_buf.take() {
state.recv_iter = Some(send_buf.into_iter());
// recv_iter.next() is guaranteed to be Some(x)
Poll::Ready(state.recv_iter.as_mut().unwrap().next())
} else if state.num_senders == 0 {
Poll::Ready(None)
} else {
state.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Factory Functions
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub fn channel<Data: ChannelData>() -> (ChannelSender<Data>, ChannelReceiver<Data>) {
let state = Arc::new(Mutex::new(ChannelState {
send_buf: None,
recv_iter: None,
num_senders: 1,
waker: None,
}));
(ChannelSender(state.clone()), ChannelReceiver(state))
}
pub fn set_channel<T: Eq + Hash + Send + Sync>(
) -> (ChannelSender<HashSet<T>>, ChannelReceiver<HashSet<T>>) {
channel::<HashSet<T>>()
}
pub fn queue_channel<T: Send + Sync>() -> (ChannelSender<Vec<T>>, ChannelReceiver<Vec<T>>) {
channel::<Vec<T>>()
}
pub fn singleton_channel<T: Send + Sync>() -> (ChannelSender<Option<T>>, ChannelReceiver<Option<T>>)
{
channel::<Option<T>>()
}

71
src/view/grid/mod.rs Normal file
View File

@ -0,0 +1,71 @@
use {
crate::view::index::{IndexArea, IndexView},
cgmath::Point2,
std::{
cmp::{max, min},
ops::RangeInclusive,
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait GridView = IndexView<Point2<i16>>;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub mod window_iterator;
pub use window_iterator::GridWindowIterator;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl IndexArea<Point2<i16>> {
// todo: this is not perfect (e.g. diagonals are inefficient)
pub fn iter(&self) -> GridWindowIterator {
GridWindowIterator::from(self.range())
}
pub fn range(&self) -> RangeInclusive<Point2<i16>> {
match self {
IndexArea::Empty => Point2::new(0, 0)..=Point2::new(-1, -1),
IndexArea::Full => panic!("range from full grid area"),
IndexArea::Set(v) => {
Point2::new(
v.iter().map(|p| p.x).min().unwrap_or(i16::MAX),
v.iter().map(|p| p.y).min().unwrap_or(i16::MAX),
)
..=Point2::new(
v.iter().map(|p| p.x).max().unwrap_or(i16::MIN),
v.iter().map(|p| p.y).max().unwrap_or(i16::MIN),
)
}
IndexArea::Range(r) => r.clone(),
}
}
pub fn union(self, other: IndexArea<Point2<i16>>) -> IndexArea<Point2<i16>> {
match (self, other) {
(IndexArea::Empty, a) | (a, IndexArea::Empty) => a,
(IndexArea::Full, _) | (_, IndexArea::Full) => IndexArea::Full,
(IndexArea::Set(mut va), IndexArea::Set(vb)) => {
va.extend(vb.into_iter());
IndexArea::Set(va)
}
(IndexArea::Range(r), IndexArea::Set(mut v))
| (IndexArea::Set(mut v), IndexArea::Range(r)) => {
v.extend(GridWindowIterator::from(r));
IndexArea::Set(v)
}
(IndexArea::Range(ra), IndexArea::Range(rb)) => IndexArea::Range(
Point2::new(
min(ra.start().x, rb.start().x),
min(ra.start().y, rb.start().y),
)
..=Point2::new(max(ra.end().x, rb.end().x), max(ra.end().y, rb.end().y)),
),
}
}
}

View File

@ -0,0 +1,58 @@
use {
cgmath::Point2,
std::ops::{Range, RangeInclusive},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct GridWindowIterator {
next: Point2<i16>,
range: Range<Point2<i16>>,
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl From<Range<Point2<i16>>> for GridWindowIterator {
fn from(range: Range<Point2<i16>>) -> Self {
GridWindowIterator {
next: range.start,
range,
}
}
}
impl From<RangeInclusive<Point2<i16>>> for GridWindowIterator {
fn from(range: RangeInclusive<Point2<i16>>) -> Self {
GridWindowIterator {
next: *range.start(),
range: *range.start()..Point2::new(range.end().x + 1, range.end().y + 1),
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl Iterator for GridWindowIterator {
type Item = Point2<i16>;
fn next(&mut self) -> Option<Point2<i16>> {
if self.next.y < self.range.end.y {
if self.next.x < self.range.end.x {
let next = self.next;
if self.next.x + 1 < self.range.end.x {
self.next.x += 1;
} else {
self.next.x = self.range.start.x;
self.next.y += 1;
}
Some(next)
} else {
None
}
} else {
None
}
}
}

126
src/view/index/mod.rs Normal file
View File

@ -0,0 +1,126 @@
use {
crate::view::View,
std::sync::RwLock,
std::{
ops::{Deref, RangeInclusive},
sync::Arc,
},
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub enum IndexArea<Key> {
Empty,
Full,
Set(Vec<Key>),
Range(RangeInclusive<Key>),
//Procedural(Arc<dyn Fn() -> Box<dyn Iterator<Item = Key>>>)
}
impl<Key> IndexArea<Key> {
pub fn map<T>(&self, f: impl Fn(&Key) -> T) -> IndexArea<T> {
match self {
IndexArea::Empty => IndexArea::Empty,
IndexArea::Full => IndexArea::Full,
IndexArea::Set(v) => IndexArea::Set(v.iter().map(&f).collect()),
IndexArea::Range(r) => IndexArea::Range(f(&r.start())..=f(&r.end())),
}
}
}
pub trait IndexView<Key>: View<Msg = IndexArea<Key>>
where
Key: Send + Sync,
{
type Item;
fn get(&self, key: &Key) -> Option<Self::Item>;
fn area(&self) -> IndexArea<Key> {
IndexArea::Full
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Key, V> IndexView<Key> for RwLock<V>
where
Key: Send + Sync,
V: IndexView<Key> + ?Sized,
{
type Item = V::Item;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.read().unwrap().get(key)
}
fn area(&self) -> IndexArea<Key> {
self.read().unwrap().area()
}
}
impl<Key, V> IndexView<Key> for Arc<V>
where
Key: Send + Sync,
V: IndexView<Key> + ?Sized,
{
type Item = V::Item;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.deref().get(key)
}
fn area(&self) -> IndexArea<Key> {
self.deref().area()
}
}
impl<Key, V> IndexView<Key> for Option<V>
where
Key: Send + Sync,
V: IndexView<Key>,
{
type Item = V::Item;
fn get(&self, key: &Key) -> Option<Self::Item> {
self.as_ref()?.get(key)
}
fn area(&self) -> IndexArea<Key> {
if let Some(v) = self.as_ref() {
v.area()
} else {
IndexArea::Empty
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/*
pub trait ImplIndexView : Send + Sync {
type Key : Send + Sync;
type Value;
fn get(&self, key: &Self::Key) -> Option<Self::Value>;
fn area(&self) -> Option<Vec<Self::Key>> {
None
}
}
impl<V: ImplIndexView> View for V {
type Msg = V::Key;
}
impl<V: ImplIndexView> IndexView<V::Key> for V {
type Item = V::Value;
fn get(&self, key: &V::Key) -> Option<Self::Item> {
(self as &V).get(key)
}
fn area(&self) -> Option<Vec<V::Key>> {
(self as &V).area()
}
}
*/

46
src/view/mod.rs Normal file
View File

@ -0,0 +1,46 @@
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
View
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub trait View: Send + Sync {
/// Notification message for the observers
type Msg: Send + Sync;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use std::sync::{Arc, RwLock};
impl<V: View + ?Sized> View for RwLock<V> {
type Msg = V::Msg;
}
impl<V: View + ?Sized> View for Arc<V> {
type Msg = V::Msg;
}
impl<V: View> View for Option<V> {
type Msg = V::Msg;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub mod channel;
pub mod observer;
pub mod port;
pub use {
channel::{queue_channel, set_channel, singleton_channel, ChannelReceiver, ChannelSender},
observer::{NotifyFnObserver, Observer, ObserverBroadcast, ObserverExt, ResetFnObserver},
port::{AnyInnerViewPort, AnyOuterViewPort, AnyViewPort, InnerViewPort, OuterViewPort, ViewPort}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub mod singleton;
pub mod sequence;
pub mod index;
pub mod grid;

179
src/view/observer.rs Normal file
View File

@ -0,0 +1,179 @@
use {
crate::view::{
channel::{channel, ChannelReceiver, ChannelSender},
View,
},
std::sync::RwLock,
std::sync::{Arc, Weak},
};
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Observer
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub trait Observer<V: View + ?Sized>: Send + Sync {
fn reset(&mut self, _view: Option<Arc<V>>) {}
fn notify(&mut self, msg: &V::Msg);
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized, O: Observer<V>> Observer<V> for Arc<RwLock<O>> {
fn reset(&mut self, view: Option<Arc<V>>) {
self.write().unwrap().reset(view);
}
fn notify(&mut self, msg: &V::Msg) {
self.write().unwrap().notify(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait ObserverExt<V: View + ?Sized>: Observer<V> {
fn notify_each(&mut self, it: impl IntoIterator<Item = V::Msg>);
}
impl<V: View + ?Sized, T: Observer<V>> ObserverExt<V> for T {
fn notify_each(&mut self, it: impl IntoIterator<Item = V::Msg>) {
for msg in it {
self.notify(&msg);
}
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Broadcast
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub struct ObserverBroadcast<V: View + ?Sized>
where
V::Msg: Send + Sync,
{
rx: ChannelReceiver<Vec<V::Msg>>,
tx: ChannelSender<Vec<V::Msg>>,
observers: Vec<Weak<RwLock<dyn Observer<V>>>>,
}
impl<V: View + ?Sized> ObserverBroadcast<V>
where
V::Msg: Clone + Send + Sync,
{
pub fn new() -> Self {
let (tx, rx) = channel::<Vec<V::Msg>>();
ObserverBroadcast {
rx,
tx,
observers: Vec::new(),
}
}
pub fn add_observer(&mut self, obs: Weak<RwLock<dyn Observer<V>>>) {
self.cleanup();
self.observers.push(obs);
}
fn cleanup(&mut self) {
self.observers.retain(|o| o.strong_count() > 0);
}
fn iter(&self) -> impl Iterator<Item = Arc<RwLock<dyn Observer<V>>>> + '_ {
self.observers.iter().filter_map(|o| o.upgrade())
}
pub fn update(&self) {
if let Some(msg_vec) = self.rx.try_recv() {
for msg in msg_vec {
for o in self.iter() {
o.write().unwrap().notify(&msg);
}
}
}
}
}
impl<V: View + ?Sized> Observer<V> for ObserverBroadcast<V>
where
V::Msg: Clone,
{
fn reset(&mut self, view: Option<Arc<V>>) {
for o in self.iter() {
o.write().unwrap().reset(view.clone());
}
}
fn notify(&mut self, msg: &V::Msg) {
self.tx.send(msg.clone());
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct NotifyFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(&V::Msg) + Send + Sync,
{
f: F,
_phantom: std::marker::PhantomData<V>,
}
impl<V, F> NotifyFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(&V::Msg) + Send + Sync,
{
pub fn new(f: F) -> Self {
NotifyFnObserver {
f,
_phantom: std::marker::PhantomData,
}
}
}
impl<V, F> Observer<V> for NotifyFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(&V::Msg) + Send + Sync,
{
fn notify(&mut self, msg: &V::Msg) {
(self.f)(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct ResetFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(Option<Arc<V>>) + Send + Sync,
{
f: F,
_phantom: std::marker::PhantomData<V>,
}
impl<V, F> ResetFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(Option<Arc<V>>) + Send + Sync,
{
pub fn new(f: F) -> Self {
ResetFnObserver {
f,
_phantom: std::marker::PhantomData,
}
}
}
impl<V, F> Observer<V> for ResetFnObserver<V, F>
where
V: View + ?Sized,
F: Fn(Option<Arc<V>>) + Send + Sync,
{
fn notify(&mut self, _msg: &V::Msg) {}
fn reset(&mut self, view: Option<Arc<V>>) {
(self.f)(view);
}
}

340
src/view/port.rs Normal file
View File

@ -0,0 +1,340 @@
use {
crate::view::{NotifyFnObserver, Observer, ObserverBroadcast, ResetFnObserver, View},
std::any::Any,
std::sync::{Arc, RwLock}
};
pub trait UpdateTask: Send + Sync {
fn update(&self);
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
View Port
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub struct ViewPort<V: View + ?Sized> {
view: Arc<RwLock<Option<Arc<V>>>>,
cast: Arc<RwLock<ObserverBroadcast<V>>>,
pub update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
}
impl<V: View + ?Sized> ViewPort<V>
where
V::Msg: Clone,
{
pub fn new() -> Self {
ViewPort {
view: Arc::new(RwLock::new(None)),
cast: Arc::new(RwLock::new(ObserverBroadcast::new())),
update_hooks: Arc::new(RwLock::new(Vec::new())),
}
}
pub fn with_view(view: Arc<V>) -> Self {
let port = ViewPort::new();
port.set_view(Some(view));
port
}
pub fn set_view(&self, view: Option<Arc<V>>) {
self.update();
*self.view.write().unwrap() = view.clone();
self.cast.write().unwrap().reset(view);
}
pub fn get_cast(&self) -> Arc<RwLock<ObserverBroadcast<V>>> {
self.cast.clone()
}
pub fn add_observer(&self, observer: Arc<RwLock<dyn Observer<V>>>) {
self.update();
self.cast
.write()
.unwrap()
.add_observer(Arc::downgrade(&observer));
observer
.write()
.unwrap()
.reset(self.view.read().unwrap().clone());
}
pub fn add_update_hook(&self, hook_cast: Arc<dyn UpdateTask>) {
self.update_hooks.write().unwrap().push(hook_cast);
}
pub fn inner(&self) -> InnerViewPort<V> {
InnerViewPort(ViewPort {
view: self.view.clone(),
cast: self.cast.clone(),
update_hooks: self.update_hooks.clone(),
})
}
pub fn outer(&self) -> OuterViewPort<V> {
OuterViewPort(ViewPort {
view: self.view.clone(),
cast: self.cast.clone(),
update_hooks: self.update_hooks.clone(),
})
}
pub fn into_inner(self) -> InnerViewPort<V> {
InnerViewPort(ViewPort {
view: self.view,
cast: self.cast,
update_hooks: self.update_hooks,
})
}
pub fn into_outer(self) -> OuterViewPort<V> {
OuterViewPort(ViewPort {
view: self.view,
cast: self.cast,
update_hooks: self.update_hooks,
})
}
}
impl<V: View + ?Sized> UpdateTask for ViewPort<V>
where
V::Msg: Clone + Send + Sync,
{
fn update(&self) {
let v = {
let t = self.update_hooks.read().unwrap();
t.iter().cloned().collect::<Vec<_>>()
};
for hook in v {
hook.update();
}
self.cast.read().unwrap().update();
}
}
impl<V: View + ?Sized> Clone for ViewPort<V>
where
V::Msg: Clone,
{
fn clone(&self) -> Self {
ViewPort {
view: self.view.clone(),
cast: self.cast.clone(),
update_hooks: self.update_hooks.clone(),
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct InnerViewPort<V: View + ?Sized>(pub ViewPort<V>)
where
V::Msg: Clone;
pub struct OuterViewPort<V: View + ?Sized>(pub ViewPort<V>)
where
V::Msg: Clone;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized> InnerViewPort<V>
where
V::Msg: Clone,
{
pub fn get_broadcast(&self) -> Arc<RwLock<ObserverBroadcast<V>>> {
self.0.cast.clone()
}
pub fn set_view(&self, view: Option<Arc<V>>) -> Arc<RwLock<ObserverBroadcast<V>>> {
self.0.set_view(view);
self.get_broadcast()
}
pub fn get_view(&self) -> Option<Arc<V>> {
self.0.view.read().unwrap().clone()
}
pub fn notify(&self, msg: &V::Msg) {
self.0.cast.write().unwrap().notify(msg);
}
}
impl<V: View + ?Sized> Clone for InnerViewPort<V>
where
V::Msg: Clone,
{
fn clone(&self) -> Self {
InnerViewPort(self.0.clone())
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized + 'static> OuterViewPort<V>
where
V::Msg: Clone,
{
pub fn get_view(&self) -> Option<Arc<V>> {
self.0.view.read().unwrap().clone()
}
pub fn get_view_arc(&self) -> Arc<RwLock<Option<Arc<V>>>> {
self.0.view.clone()
}
pub fn add_observer(
&self,
observer: Arc<RwLock<dyn Observer<V>>>,
) -> Arc<RwLock<Option<Arc<V>>>> {
self.0.add_observer(observer);
self.get_view_arc()
}
pub fn add_reset_fn<F: Fn(Option<Arc<V>>) + Send + Sync + 'static>(
&self,
reset: F,
) -> Arc<RwLock<ResetFnObserver<V, F>>> {
let obs = Arc::new(RwLock::new(ResetFnObserver::new(reset)));
self.add_observer(obs.clone());
obs
}
pub fn add_notify_fn<F: Fn(&V::Msg) + Send + Sync + 'static>(
&self,
notify: F,
) -> Arc<RwLock<NotifyFnObserver<V, F>>> {
let obs = Arc::new(RwLock::new(NotifyFnObserver::new(notify)));
self.add_observer(obs.clone());
obs
}
}
impl<V: View + ?Sized> Clone for OuterViewPort<V>
where
V::Msg: Clone,
{
fn clone(&self) -> Self {
OuterViewPort(self.0.clone())
}
}
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 {
pub fn into_stream<Data>(
self,
reset: impl Fn(Option<Arc<V>>, ChannelSender<Data>) + Send + Sync + 'static
) -> ChannelReceiver<Data>
where Data: ChannelData<Item = V::Msg> + 'static,
Data::IntoIter: Send + Sync + 'static
{
let (s, r) = crate::core::channel::channel::<Data>();
self.add_observer(Arc::new(s.clone()));
self.add_reset_fn(
move |view| { reset(view, s.clone()); }
);
r
}
}
*/
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct AnyViewPort {
view: Arc<dyn Any + Send + Sync + 'static>,
cast: Arc<dyn Any + Send + Sync + 'static>,
update_hooks: Arc<RwLock<Vec<Arc<dyn UpdateTask>>>>,
}
impl AnyViewPort {
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<ViewPort<V>, AnyViewPort> {
match (
self.view.clone().downcast::<RwLock<Option<Arc<V>>>>(),
self.cast.clone().downcast::<RwLock<ObserverBroadcast<V>>>(),
self.update_hooks.clone(),
) {
(Ok(view), Ok(cast), update_hooks) => Ok(ViewPort {
view,
cast,
update_hooks,
}),
_ => Err(self),
}
}
}
impl<V: View + ?Sized + 'static> From<ViewPort<V>> for AnyViewPort {
fn from(port: ViewPort<V>) -> Self {
AnyViewPort {
view: port.view as Arc<dyn Any + Send + Sync + 'static>,
cast: port.cast as Arc<dyn Any + Send + Sync + 'static>,
update_hooks: port.update_hooks,
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct AnyOuterViewPort(AnyViewPort);
#[derive(Clone)]
pub struct AnyInnerViewPort(AnyViewPort);
impl AnyOuterViewPort {
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<OuterViewPort<V>, AnyViewPort>
where
V::Msg: Clone,
{
Ok(OuterViewPort(self.0.downcast::<V>()?))
}
}
impl<V: View + ?Sized + 'static> From<OuterViewPort<V>> for AnyOuterViewPort
where
V::Msg: Clone,
{
fn from(port: OuterViewPort<V>) -> Self {
AnyOuterViewPort(AnyViewPort {
view: port.0.view as Arc<dyn Any + Send + Sync + 'static>,
cast: port.0.cast as Arc<dyn Any + Send + Sync + 'static>,
update_hooks: port.0.update_hooks,
})
}
}
impl AnyInnerViewPort {
pub fn downcast<V: View + ?Sized + 'static>(self) -> Result<InnerViewPort<V>, AnyViewPort>
where
V::Msg: Clone,
{
Ok(InnerViewPort(self.0.downcast::<V>()?))
}
}
impl<V: View + ?Sized + 'static> From<InnerViewPort<V>> for AnyInnerViewPort
where
V::Msg: Clone,
{
fn from(port: InnerViewPort<V>) -> Self {
AnyInnerViewPort(AnyViewPort {
view: port.0.view as Arc<dyn Any + Send + Sync + 'static>,
cast: port.0.cast as Arc<dyn Any + Send + Sync + 'static>,
update_hooks: port.0.update_hooks,
})
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>

87
src/view/sequence/mod.rs Normal file
View File

@ -0,0 +1,87 @@
use crate::view::View;
pub trait SequenceView: View<Msg = usize> {
type Item;
fn get(&self, idx: &usize) -> Option<Self::Item>;
fn len(&self) -> Option<usize>;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait SequenceViewExt: SequenceView {
fn iter<'a>(&'a self) -> SequenceViewIter<'a, Self> {
SequenceViewIter { view: self, cur: 0 }
}
}
impl<V: SequenceView + ?Sized> SequenceViewExt for V {}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct SequenceViewIter<'a, V>
where
V: SequenceView + ?Sized,
{
view: &'a V,
cur: usize,
}
impl<'a, V> Iterator for SequenceViewIter<'a, V>
where
V: SequenceView + ?Sized,
{
type Item = V::Item;
fn next(&mut self) -> Option<Self::Item> {
let i = self.cur;
self.cur += 1;
self.view.get(&i)
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use std::sync::RwLock;
use std::{ops::Deref, sync::Arc};
impl<V: SequenceView + ?Sized> SequenceView for RwLock<V> {
type Item = V::Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
self.read().unwrap().get(idx)
}
fn len(&self) -> Option<usize> {
self.read().unwrap().len()
}
}
impl<V: SequenceView + ?Sized> SequenceView for Arc<V> {
type Item = V::Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
self.deref().get(idx)
}
fn len(&self) -> Option<usize> {
self.deref().len()
}
}
impl<V: SequenceView> SequenceView for Option<V> {
type Item = V::Item;
fn get(&self, idx: &usize) -> Option<Self::Item> {
(self.as_ref()? as &V).get(idx)
}
fn len(&self) -> Option<usize> {
if let Some(v) = self.as_ref() {
v.len()
} else {
Some(0)
}
}
}

57
src/view/singleton/mod.rs Normal file
View File

@ -0,0 +1,57 @@
use {
crate::{view::View},
std::{ops::Deref, sync::{Arc, RwLock}},
};
// TODO: #[ImplForArc, ImplForRwLock]
pub trait SingletonView: View<Msg = ()> {
type Item;
fn get(&self) -> Self::Item;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: SingletonView + ?Sized> SingletonView for RwLock<V> {
type Item = V::Item;
fn get(&self) -> Self::Item {
self.read().unwrap().get()
}
}
impl<V: SingletonView + ?Sized> SingletonView for Arc<V> {
type Item = V::Item;
fn get(&self) -> Self::Item {
self.deref().get()
}
}
impl<V: SingletonView> SingletonView for Option<V>
where
V::Item: Default,
{
type Item = V::Item;
fn get(&self) -> Self::Item {
if let Some(s) = self.as_ref() {
s.get()
} else {
V::Item::default()
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/*
impl<T> OuterViewPort<dyn SingletonView<Item = T>> {
pub fn get(&self) -> T {
self.get_view().unrwap().read().unwrap().get();
}
pub fn map<U: Send + Sync + 'static>(&self, f: impl Fn(T) -> U) -> OuterViewPort<dyn SingletonView<Item = U>> {
}
}
*/

1
src/view/view.rs Normal file
View File

@ -0,0 +1 @@