refactoring

This commit is contained in:
Michael Sippel 2021-01-06 21:35:46 +01:00
parent cdd06eb9b8
commit 86562614cc
Signed by: senvas
GPG key ID: F96CF119C34B64A6
18 changed files with 1071 additions and 558 deletions

View file

@ -6,10 +6,10 @@ name = "NeStEd"
version = "0.1.0" version = "0.1.0"
[dependencies] [dependencies]
cgmath = "*" cgmath = "0.17.0"
termion = "*" termion = "1.5.5"
signal-hook = "*" signal-hook = "0.3.1"
signal-hook-async-std = "*" signal-hook-async-std = "0.2.0"
[dependencies.async-std] [dependencies.async-std]
version = "1.7.0" version = "1.7.0"

View file

@ -13,7 +13,7 @@ use {
}, },
crate::{ crate::{
view::{Observer} core::{Observer}
} }
}; };
@ -83,11 +83,9 @@ pub struct ChannelReceiver<Data: ChannelData>(Arc<Mutex<ChannelState<Data>>>);
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Data: ChannelData> Observer for ChannelSender<Data> impl<Data: ChannelData> ChannelSender<Data>
where Data::IntoIter: Send + Sync { where Data::IntoIter: Send + Sync {
type Msg = Data::Item; pub fn send(&self, msg: Data::Item) {
fn notify(&self, msg: Data::Item) {
let mut state = self.0.lock().unwrap(); let mut state = self.0.lock().unwrap();
if state.send_buf.is_none() { if state.send_buf.is_none() {
@ -102,6 +100,14 @@ where Data::IntoIter: Send + Sync {
} }
} }
use crate::core::View;
impl<V: View + ?Sized, Data: ChannelData<Item = V::Msg>> Observer<V> for ChannelSender<Data>
where V::Msg: Clone, Data::IntoIter: Send + Sync {
fn notify(&self, msg: &V::Msg) {
self.send(msg.clone());
}
}
impl<Data: ChannelData> Clone for ChannelSender<Data> { impl<Data: ChannelData> Clone for ChannelSender<Data> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
self.0.lock().unwrap().num_senders += 1; self.0.lock().unwrap().num_senders += 1;

30
src/core/mod.rs Normal file
View file

@ -0,0 +1,30 @@
pub mod view;
pub mod observer;
pub mod channel;
pub mod port;
pub use {
view::{View},
observer::{
Observer,
ObserverExt,
ObserverBroadcast,
NotifyFnObserver,
ResetFnObserver
},
channel::{
ChannelReceiver,
ChannelSender,
set_channel,
queue_channel,
singleton_channel
},
port::{
ViewPort,
InnerViewPort,
OuterViewPort
}
};

149
src/core/observer.rs Normal file
View file

@ -0,0 +1,149 @@
use {
crate::core::View,
std::{
ops::Deref,
sync::{Arc, Weak, RwLock}
}
};
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Observer
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub trait Observer<V: View + ?Sized> : Send + Sync {
fn reset(&self, view: Option<Arc<V>>) {}
fn notify(&self, msg: &V::Msg);
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized, O: Observer<V>> Observer<V> for RwLock<O> {
fn notify(&self, msg: &V::Msg) {
self.read().unwrap().notify(&msg);
}
}
impl<V: View + ?Sized, O: Observer<V>> Observer<V> for Arc<O> {
fn notify(&self, msg: &V::Msg) {
self.deref().notify(&msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait ObserverExt<V: View + ?Sized> : Observer<V> {
fn notify_each(&self, it: impl IntoIterator<Item = V::Msg>);
}
impl<V: View + ?Sized, T: Observer<V>> ObserverExt<V> for T {
fn notify_each(&self, it: impl IntoIterator<Item = V::Msg>) {
for msg in it {
self.notify(&msg);
}
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Broadcast
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub struct ObserverBroadcast<V: View + ?Sized> {
observers: Vec<Weak<dyn Observer<V>>>
}
impl<V: View + ?Sized> ObserverBroadcast<V> {
pub fn new() -> Self {
ObserverBroadcast {
observers: Vec::new()
}
}
pub fn add_observer(&mut self, obs: Weak<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<dyn Observer<V>>> + '_ {
self.observers.iter().filter_map(|o| o.upgrade())
}
}
impl<V: View + ?Sized> Observer<V> for ObserverBroadcast<V> {
fn reset(&self, view: Option<Arc<V>>) {
for o in self.iter() {
o.reset(view.clone());
}
}
fn notify(&self, msg: &V::Msg) {
for o in self.iter() {
o.notify(&msg);
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
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(&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(&self, msg: &V::Msg) {}
fn reset(&self, view: Option<Arc<V>>) {
(self.f)(view);
}
}

144
src/core/port.rs Normal file
View file

@ -0,0 +1,144 @@
use {
std::sync::{Arc, RwLock},
crate::core::{
View,
Observer,
ObserverBroadcast,
NotifyFnObserver,
ResetFnObserver,
channel::{
ChannelData,
ChannelSender,
ChannelReceiver
}
}
};
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
View Port
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
#[derive(Clone)]
pub struct ViewPort<V: View + ?Sized> {
view: Arc<RwLock<Option<Arc<V>>>>,
observers: Arc<RwLock<ObserverBroadcast<V>>>
}
impl<V: View + ?Sized> ViewPort<V> {
pub fn new() -> Self {
ViewPort {
view: Arc::new(RwLock::new(None)),
observers: Arc::new(RwLock::new(ObserverBroadcast::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.view.write().unwrap() = view.clone();
self.observers.read().unwrap().reset(view);
}
pub fn add_observer(&self, observer: Arc<dyn Observer<V>>) {
self.observers.write().unwrap().add_observer(Arc::downgrade(&observer));
observer.reset(self.view.read().unwrap().clone());
}
pub fn inner(&self) -> InnerViewPort<V> {
InnerViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
}
pub fn outer(&self) -> OuterViewPort<V> {
OuterViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
}
pub fn into_inner(self) -> InnerViewPort<V> {
InnerViewPort(ViewPort{ view: self.view, observers: self.observers })
}
pub fn into_outer(self) -> OuterViewPort<V> {
OuterViewPort(ViewPort{ view: self.view, observers: self.observers })
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct InnerViewPort<V: View + ?Sized>(ViewPort<V>);
#[derive(Clone)]
pub struct OuterViewPort<V: View + ?Sized>(ViewPort<V>);
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized> InnerViewPort<V> {
pub fn get_broadcast(&self) -> Arc<RwLock<ObserverBroadcast<V>>> {
self.0.observers.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.observers.read().unwrap().notify(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: View + ?Sized + 'static> OuterViewPort<V> {
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<dyn Observer<V>>) -> Arc<RwLock<Option<Arc<V>>>> {
self.0.add_observer(observer);
self.get_view_arc()
}
/*
pub fn add_reset_fn(&self, reset: impl Fn(Option<Arc<V>>) + Send + Sync + 'static) -> Arc<RwLock<Option<Arc<V>>>> {
self.add_observer(Arc::new(ResetFnObserver::new(reset)))
}
pub fn add_notify_fn(&self, notify: impl Fn(&V::Msg) + Send + Sync + 'static) -> Arc<RwLock<Option<Arc<V>>>> {
self.add_observer(Arc::new(NotifyFnObserver::new(notify)))
}
*/
}
/*
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
}
}
*/

24
src/core/view.rs Normal file
View file

@ -0,0 +1,24 @@
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
View
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
pub trait View : Send + Sync {
/// Notification message for the observers
type Msg;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use std::sync::{Arc, RwLock};
impl<V: View> View for RwLock<V> {
type Msg = V::Msg;
}
impl<V: View> View for Arc<V> {
type Msg = V::Msg;
}

View file

@ -1,51 +1,104 @@
#![feature(trait_alias)] #![feature(trait_alias)]
#![feature(assoc_char_funcs)] #![feature(assoc_char_funcs)]
pub mod core;
pub mod view; pub mod view;
pub mod port;
pub mod channel;
pub mod singleton_buffer;
pub mod vec_buffer;
pub mod terminal; pub mod terminal;
pub mod string_editor; pub mod string_editor;
//pub mod singleton_buffer;
//pub mod vec_buffer;
//pub mod sequence_element_projection;
use { use {
async_std::{task}, async_std::{task},
std::{ std::{
sync::{Arc, RwLock} sync::{Arc, RwLock},
ops::Range
}, },
cgmath::{Vector2}, cgmath::{Vector2, Point2},
termion::event::{Event, Key},
crate::{ crate::{
view::{View, Observer}, core::{View, Observer, ObserverExt, ViewPort},
port::{ViewPort, InnerViewPort, OuterViewPort}, view::{*},
singleton_buffer::SingletonBuffer,
vec_buffer::VecBuffer,
terminal::{ terminal::{
Terminal, TerminalView,
TerminalAtom, TerminalAtom,
TerminalStyle, TerminalStyle,
TerminalCompositor, TerminalEvent,
TerminalEvent Terminal,
} TerminalCompositor
}, },
termion::event::{Event, Key} }
}; };
struct Fill(TerminalAtom); struct VecSequenceView<T: Send + Sync + Clone>(Arc<RwLock<Vec<T>>>);
impl View for Fill { impl<T: Send + Sync + Clone> ImplIndexView for VecSequenceView<T> {
type Key = Vector2<i16>; type Key = usize;
type Value = TerminalAtom; type Value = T;
fn view(&self, _: Vector2<i16>) -> Option<TerminalAtom> { fn get(&self, idx: &usize) -> T {
Some(self.0.clone()) self.0.read().unwrap()[*idx].clone()
}
fn range(&self) -> Option<Range<usize>> {
Some(0 .. self.0.read().unwrap().len())
}
}
struct Checkerboard;
impl ImplIndexView for Checkerboard {
type Key = Point2<i16>;
type Value = Option<TerminalAtom>;
fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
if pos.x == 0 || pos.x == 1 || pos.x > 17 || pos.y == 0 || pos.y > 8 {
// border
Some(TerminalAtom::new_bg((20, 10, 10)))
} else {
// field
if ((pos.x/2) % 2 == 0) ^ ( pos.y % 2 == 0 ) {
Some(TerminalAtom::new_bg((0, 0, 0)))
} else {
Some(TerminalAtom::new_bg((200, 200, 200)))
}
}
}
fn range(&self) -> Option<Range<Point2<i16>>> {
Some(Point2::new(0,0) .. Point2::new(20,10))
}
}
struct ScrambleBackground;
impl ImplIndexView for ScrambleBackground {
type Key = Point2<i16>;
type Value = Option<TerminalAtom>;
fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
if ((pos.x/2) % 2 == 0) ^ ( pos.y % 2 == 0 ) {
Some(TerminalAtom::new(char::from((35+(5*pos.y+pos.x)%40) as u8), TerminalStyle::fg_color((40, 40, 40))))
} else {
Some(TerminalAtom::new(char::from((35+(pos.y+9*pos.x)%40) as u8), TerminalStyle::fg_color((90, 90, 90))))
}
}
fn range(&self) -> Option<Range<Point2<i16>>> {
None
//Some(Point2::new(0,0) .. Point2::new(50,30))
} }
} }
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
let composite_view = port::ViewPort::new(); let term_port = ViewPort::<dyn TerminalView>::new();
let mut compositor = TerminalCompositor::new(composite_view.inner());
let mut compositor = TerminalCompositor::new(term_port.inner());
compositor.push(ViewPort::<dyn TerminalView>::with_view(Arc::new(ScrambleBackground)).into_outer());
let mut term = Terminal::new(term_port.outer());
let term_writer = term.get_writer();
task::spawn(async move { task::spawn(async move {
/*\ /*\
@ -53,36 +106,30 @@ async fn main() {
Setup Views Setup Views
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/ \*/
let fp = port::ViewPort::with_view(Arc::new(Fill(TerminalAtom::new('.', TerminalStyle::fg_color((50,50,50))))));
compositor.push(fp.outer());
let ep = port::ViewPort::new(); compositor.push(ViewPort::<dyn TerminalView>::with_view(Arc::new(Checkerboard)).into_outer());
let mut editor = string_editor::StringEditor::new(ep.inner()); let edit_port = ViewPort::<dyn TerminalView>::new();
compositor.push(ep.outer()); let mut editor = string_editor::StringEditor::new(edit_port.inner());
compositor.push(edit_port.into_outer());
/*\ /*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Event Loop Event Loop
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/ \*/
let mut term = Terminal::new();
loop { loop {
match term.next_event().await { match term.next_event().await {
TerminalEvent::Resize(size) => {
for x in 0 .. size.x {
for y in 0 .. size.y {
fp.inner().notify(Vector2::new(x,y));
}
}
},
TerminalEvent::Input(Event::Key(Key::Left)) => editor.prev(), TerminalEvent::Input(Event::Key(Key::Left)) => editor.prev(),
TerminalEvent::Input(Event::Key(Key::Right)) => editor.next(), TerminalEvent::Input(Event::Key(Key::Right)) => editor.next(),
TerminalEvent::Input(Event::Key(Key::Home)) => editor.goto(0), TerminalEvent::Input(Event::Key(Key::Home)) => editor.goto(0),
TerminalEvent::Input(Event::Key(Key::End)) => editor.goto_end(), TerminalEvent::Input(Event::Key(Key::End)) => editor.goto_end(),
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {},
TerminalEvent::Input(Event::Key(Key::Char(c))) => editor.insert(c), TerminalEvent::Input(Event::Key(Key::Char(c))) => editor.insert(c),
TerminalEvent::Input(Event::Key(Key::Delete)) => editor.delete(), TerminalEvent::Input(Event::Key(Key::Delete)) => editor.delete(),
TerminalEvent::Input(Event::Key(Key::Backspace)) => { editor.prev(); editor.delete(); }, TerminalEvent::Input(Event::Key(Key::Backspace)) => { editor.prev(); editor.delete(); },
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => break, TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => {
break
}
_ => {} _ => {}
} }
} }
@ -93,6 +140,6 @@ async fn main() {
Terminal Rendering Terminal Rendering
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> <<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/ \*/
Terminal::show(composite_view.into_outer()).await.ok(); term_writer.show().await.ok();
} }

View file

@ -1,186 +0,0 @@
use {
std::{
sync::{Arc, RwLock},
collections::HashSet,
hash::Hash,
},
crate::{
view::{View, Observer, FnView, FnObserver},
channel::{ChannelReceiver}
}
};
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
View Port
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
#[derive(Clone)]
pub struct ViewPort<K: Send + Sync + 'static, V: Send + Sync + 'static> {
view: Arc<RwLock<Option<Arc<dyn View<Key = K, Value = V>>>>>,
observers: Arc<RwLock<Vec<Arc<dyn Observer<Msg = K>>>>>
}
impl<K, V> ViewPort<K, V>
where K: Send + Sync + 'static,
V: Send + Sync + 'static {
pub fn new() -> Self {
ViewPort {
view: Arc::new(RwLock::new(None)),
observers: Arc::new(RwLock::new(Vec::new()))
}
}
pub fn with_view(view: Arc<dyn View<Key = K, Value = V>>) -> Self {
ViewPort {
view: Arc::new(RwLock::new(Some(view))),
observers: Arc::new(RwLock::new(Vec::new()))
}
}
pub fn set_view(&self, view: Arc<dyn View<Key = K, Value = V>>) {
*self.view.write().unwrap() = Some(view);
}
pub fn add_observer(&self, observer: Arc<dyn Observer<Msg = K>>) {
self.observers.write().unwrap().push(observer);
}
pub fn inner(&self) -> InnerViewPort<K, V> {
InnerViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
}
pub fn outer(&self) -> OuterViewPort<K, V> {
OuterViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
}
pub fn into_inner(self) -> InnerViewPort<K, V> {
InnerViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
}
pub fn into_outer(self) -> OuterViewPort<K, V> {
OuterViewPort(ViewPort{ view: self.view.clone(), observers: self.observers.clone() })
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub struct InnerViewPort<K: Send + Sync + 'static, V: Send + Sync + 'static>(ViewPort<K, V>);
#[derive(Clone)]
pub struct OuterViewPort<K: Send + Sync + 'static, V: Send + Sync + 'static>(ViewPort<K, V>);
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<K: Send + Sync + 'static, V: Send + Sync + 'static> OuterViewPort<K, V> {
pub fn get_view(&self) -> Arc<RwLock<Option<Arc<dyn View<Key = K, Value = V>>>>> {
self.0.view.clone()
}
pub fn add_observer(self, observer: Arc<dyn Observer<Msg = K>>) -> Arc<RwLock<Option<Arc<dyn View<Key = K, Value = V>>>>> {
self.0.add_observer(observer);
self.0.view
}
pub fn add_observer_fn(self, obs_fn: impl Fn(K) + Send + Sync + 'static) -> Arc<RwLock<Option<Arc<dyn View<Key = K, Value = V>>>>> {
self.add_observer(Arc::new(FnObserver::new(obs_fn)))
}
}
impl<K: Eq + Hash + Send + Sync + 'static, V: Send + Sync + 'static> OuterViewPort<K, V> {
pub fn stream(self) -> ChannelReceiver<HashSet<K>> {
let (s, r) = crate::channel::set_channel();
self.0.add_observer(Arc::new(s));
r
}
}
impl<K: Clone + Eq + Hash + Send + Sync + 'static, V: Send + Sync + 'static> OuterViewPort<K, V> {
pub fn map_value<
V2: Clone + Send + Sync + 'static,
F: Fn(Option<V>) -> Option<V2> + Send + Sync + 'static
>(
self,
f: F
) -> OuterViewPort<K, V2> {
let port = ViewPort::new();
let view = self.add_observer_fn({
let dst = port.inner();
move |key| dst.notify(key)
});
port.inner().set_view_fn(move |key| f(view.view(key)));
port.outer()
}
pub fn map_key<
K2: Clone + Send + Sync + 'static,
F1: Fn(K) -> K2 + Send + Sync + 'static,
F2: Fn(K2) -> K + Send + Sync + 'static
>(
self,
f1: F1,
f2: F2
) -> OuterViewPort<K2, V> {
let port = ViewPort::new();
let view = self.add_observer_fn({
let dst = port.inner();
move |key| dst.notify(f1(key))
});
port.inner().set_view_fn(move |key| view.view(f2(key)));
port.outer()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<K: Send + Sync + 'static, V: Send + Sync + 'static> InnerViewPort<K, V> {
pub fn set_view(&self, view: Arc<dyn View<Key = K, Value = V> + Send + Sync>) {
*self.0.view.write().unwrap() = Some(view);
}
pub fn set_view_fn(&self, view_fn: impl Fn(K) -> Option<V> + Send + Sync + 'static) {
self.set_view(Arc::new(FnView::new(view_fn)))
}
}
impl<K, V> Observer for InnerViewPort<K, V>
where K: Clone + Send + Sync + 'static,
V: Send + Sync + 'static {
type Msg = K;
fn notify(&self, msg: K) {
for observer in self.0.observers.read().unwrap().iter() {
observer.notify(msg.clone());
}
}
}
/*\
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
Stream Port
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
\*/
/*
pub struct StreamPort<T> {
actions: Vec<Arc<Mutex<dyn FnMut(T)>>>
}
impl<T> StreamPort<T> {
async fn set_stream(&self, stream: impl Stream<T>) -> impl Future<()> {
for msg in stream.next().await.unwrap() {
for act in self.actions.iter() {
(*act.lock().unwrap())(msg);
}
}
}
fn add_action(&self, action: impl FnMut(T)) {
self.actions.push(Arc::new(Mutex::new(action)))
}
}
*/

View file

@ -1,40 +1,54 @@
use { use {
std::sync::{Arc, RwLock}, std::{
cgmath::Vector2, ops::Range,
sync::{Arc, RwLock},
},
cgmath::Point2,
crate::{ crate::{
view::{View, Observer, ObserverExt}, core::{
port::{ViewPort, InnerViewPort, OuterViewPort}, View,
terminal::{TerminalAtom, TerminalStyle}, Observer,
vec_buffer::VecBuffer ObserverExt,
ObserverBroadcast,
ViewPort,
InnerViewPort,
OuterViewPort
},
sequence::SequenceView,
index::{ImplIndexView},
grid::{GridView},
terminal::{TerminalAtom, TerminalStyle, TerminalView},
//vec_buffer::VecBuffer
} }
}; };
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct StringEditorState { pub struct StringEditorState {
cursor: usize, cursor: usize,
data: Arc<RwLock<Vec<char>>> data: Arc<RwLock<Vec<char>>>
} }
impl View for StringEditorState { impl ImplIndexView for StringEditorState {
type Key = Vector2<i16>; type Key = Point2<i16>;
type Value = TerminalAtom; type Value = Option<TerminalAtom>;
fn view(&self, pos: Vector2<i16>) -> Option<TerminalAtom> { fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
if pos.y == 0 {
let cur = self.cursor;
let data = self.data.read().unwrap(); let data = self.data.read().unwrap();
if pos.y == 0 {
if pos.x < data.len() as i16 + 3 { if pos.x < data.len() as i16 + 3 {
let i = pos.x as usize; let i = pos.x as usize;
return Some( return Some(
if i == 0 { if i == 0 {
TerminalAtom::new('"', TerminalStyle::fg_color((180,200,130))) TerminalAtom::new('"', TerminalStyle::fg_color((180,200,130)))
} else if i-1 == cur { } else if i-1 == self.cursor {
TerminalAtom::new('|', TerminalStyle::fg_color((180,200,130)).add(TerminalStyle::bold(true))) TerminalAtom::new('|', TerminalStyle::fg_color((180,200,130)).add(TerminalStyle::bold(true)))
} else if i-1 == data.len()+1 { } else if i-1 == data.len()+1 {
TerminalAtom::new('"', TerminalStyle::fg_color((180,200,130))) TerminalAtom::new('"', TerminalStyle::fg_color((180,200,130)))
} else { } else {
TerminalAtom::new( TerminalAtom::new(
data.get(i as usize - if i <= cur { 1 } else { 2 }).cloned().unwrap(), data.get(i as usize - if i <= self.cursor { 1 } else { 2 }).unwrap().clone(),
TerminalStyle::fg_color((80,150,80)) TerminalStyle::fg_color((80,150,80))
) )
} }
@ -44,41 +58,34 @@ impl View for StringEditorState {
None None
} }
fn range(&self) -> Option<Range<Point2<i16>>> {
Some(
Point2::new(0, 0)
.. Point2::new(self.data.read().unwrap().len() as i16 + 3, 1)
)
}
} }
pub struct StringEditor { pub struct StringEditor {
state: Arc<RwLock<StringEditorState>>, state: Arc<RwLock<StringEditorState>>,
port: InnerViewPort<Vector2<i16>, TerminalAtom> cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
} }
impl StringEditor { impl StringEditor {
pub fn new( pub fn new(
port: InnerViewPort<Vector2<i16>, TerminalAtom> port: InnerViewPort<dyn TerminalView>
) -> Self { ) -> Self {
let state = Arc::new(RwLock::new(StringEditorState{ let state = Arc::new(RwLock::new(StringEditorState{
cursor: 0, cursor: 7,
data: Arc::new(RwLock::new(Vec::new())) data: Arc::new(RwLock::new("edit me".chars().collect()))
})); }));
/*
let buf_port = ViewPort::new();
let buf = VecBuffer::with_data(data.clone(), buf_port.inner());
buf_port.outer().add_observer_fn({ let cast = port.set_view(Some(state.clone()));
let port = port.clone();
let cursor = cursor.clone();
move |idx|
if idx < *cursor.read().unwrap() {
port.notify(Vector2::new(1 + idx as i16, 0));
} else {
port.notify(Vector2::new(2 + idx as i16, 0));
}
});
*/
port.set_view(state.clone());
StringEditor { StringEditor {
state, state,
port cast
} }
} }
@ -109,26 +116,26 @@ impl StringEditor {
old_idx old_idx
}; };
self.port.notify_each( self.cast.notify_each(
(std::cmp::min(old_idx, new_idx) ..= std::cmp::max(old_idx, new_idx)) (std::cmp::min(old_idx, new_idx) ..= std::cmp::max(old_idx, new_idx))
.map(|idx| Vector2::new(1+idx as i16, 0)) .map(|idx| Point2::new(1+idx as i16, 0))
); );
} }
pub fn insert(&mut self, c: char) { pub fn insert(&mut self, c: char) {
self.port.notify_each({ self.cast.notify_each({
let mut state = self.state.write().unwrap(); let mut state = self.state.write().unwrap();
let mut data = state.data.write().unwrap(); let mut data = state.data.write().unwrap();
data.insert(state.cursor, c); data.insert(state.cursor, c);
(state.cursor .. data.len()+2) (state.cursor .. data.len()+2)
}.map(|idx| Vector2::new(1+idx as i16, 0))); }.map(|idx| Point2::new(1+idx as i16, 0)));
self.next(); self.next();
} }
pub fn delete(&mut self) { pub fn delete(&mut self) {
self.port.notify_each({ self.cast.notify_each({
let mut state = self.state.write().unwrap(); let mut state = self.state.write().unwrap();
let mut data = state.data.write().unwrap(); let mut data = state.data.write().unwrap();
@ -136,7 +143,7 @@ impl StringEditor {
data.remove(state.cursor); data.remove(state.cursor);
} }
(state.cursor .. data.len()+3) (state.cursor .. data.len()+3)
}.map(|idx| Vector2::new(1+idx as i16, 0))); }.map(|idx| Point2::new(1+idx as i16, 0)));
} }
} }

View file

@ -1,53 +1,175 @@
use { use {
std::sync::{Arc, RwLock}, std::{
cgmath::Vector2, sync::{Arc, Weak, RwLock},
collections::HashMap,
ops::Range,
cmp::{min, max}
},
cgmath::Point2,
crate::{ crate::{
view::{View}, core::{View, ViewPort, InnerViewPort, OuterViewPort, Observer, ObserverExt, ObserverBroadcast},
port::{ViewPort, InnerViewPort, OuterViewPort}, view::{ImplIndexView, grid::GridWindowIterator},
terminal::{TerminalAtom} terminal::{TerminalAtom, TerminalView}
} }
}; };
pub struct TerminalCompositor { struct CompositeLayer {
layers: Arc<RwLock<Vec<Arc<dyn View<Key = Vector2<i16>, Value = TerminalAtom>>>>>, comp: Weak<RwLock<TerminalCompositeView>>,
port: Arc<InnerViewPort<Vector2<i16>, TerminalAtom>> idx: usize,
view: RwLock<Option<Arc<dyn TerminalView>>>
} }
impl TerminalCompositor { impl Observer<dyn TerminalView> for CompositeLayer {
pub fn new(port: InnerViewPort<Vector2<i16>, TerminalAtom>) -> Self { fn reset(&self, view: Option<Arc<dyn TerminalView>>) {
let layers = Arc::new(RwLock::new(Vec::<Arc<dyn View<Key = Vector2<i16>, Value = TerminalAtom>>>::new())); let comp = self.comp.upgrade().unwrap();
let mut c = comp.write().unwrap();
port.set_view_fn({ {
let layers = layers.clone(); let mut v = self.view.write().unwrap();
move |pos| { let old_view = v.clone();
*v = view.clone();
if let Some(old_view) = old_view {
if let Some(range) = old_view.range() {
c.cast.notify_each(GridWindowIterator::from(range));
}
}
if let Some(view) = v.as_ref() {
if let Some(range) = view.range() {
c.cast.notify_each(GridWindowIterator::from(range));
}
}
}
c.update_range();
}
fn notify(&self, pos: &Point2<i16>) {
self.comp
.upgrade().unwrap()
.read().unwrap()
.cast.notify(pos);
}
}
pub struct TerminalCompositeView {
idx_count: usize,
layers: HashMap<usize, Arc<CompositeLayer>>,
range: Option<Range<Point2<i16>>>,
cast: Arc<RwLock<ObserverBroadcast<dyn TerminalView>>>
}
impl TerminalCompositeView {
fn update_range(&mut self) {
if self.layers.len() == 0 {
self.range = Some(Point2::new(0, 0) .. Point2::new(0, 0))
} else {
self.range = None;
for (idx, layer) in self.layers.iter() {
self.range =
if let (
Some(new_range),
Some(old_range)
) = (
if let Some(view) = layer.view.read().unwrap().clone() {
view.range().clone()
} else {
None
},
self.range.as_ref()
) {
Some(
Point2::new(
min(old_range.start.x, new_range.start.x),
min(old_range.start.y, new_range.start.y)
) .. Point2::new(
max(old_range.end.x, new_range.end.x),
max(old_range.end.y, new_range.end.y)
)
)
} else {
None
};
}
}
}
}
impl ImplIndexView for TerminalCompositeView {
type Key = Point2<i16>;
type Value = Option<TerminalAtom>;
fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
let mut atom = None; let mut atom = None;
for l in layers.read().unwrap().iter() { for idx in 0 .. self.idx_count {
match (atom, l.view(pos)) { if let Some(l) = self.layers.get(&idx) {
if let Some(view) = l.view.read().unwrap().as_ref() {
if let Some(range) = view.range() {
if pos.x < range.start.x ||
pos.x >= range.end.x ||
pos.y < range.start.y ||
pos.y >= range.end.y {
continue;
}
}
match (atom, view.get(pos)) {
(None, next) => atom = next, (None, next) => atom = next,
(Some(last), Some(next)) => atom = Some(next.add_style_back(last.style)), (Some(last), Some(next)) => atom = Some(next.add_style_back(last.style)),
_ => {} _ => {}
} }
} }
}
}
atom atom
} }
});
TerminalCompositor { fn range(&self) -> Option<Range<Point2<i16>>> {
layers, self.range.clone()
port: Arc::new(port) }
} }
}
pub struct TerminalCompositor {
pub fn push(&mut self, v: OuterViewPort<Vector2<i16>, TerminalAtom>) { view: Arc<RwLock<TerminalCompositeView>>,
self.layers.write().unwrap().push(v.add_observer(self.port.clone())); port: InnerViewPort<dyn TerminalView>
} }
pub fn make_port(&mut self) -> InnerViewPort<Vector2<i16>, TerminalAtom> { impl TerminalCompositor {
let port = ViewPort::new(); pub fn new(
self.push(port.outer()); port: InnerViewPort<dyn TerminalView>
port.inner() ) -> Self {
let view = Arc::new(RwLock::new(
TerminalCompositeView {
idx_count: 0,
layers: HashMap::new(),
range: Some(Point2::new(0, 0) .. Point2::new(0, 0)),
cast: port.get_broadcast()
}
));
port.set_view(Some(view.clone()));
TerminalCompositor{ view, port }
}
pub fn push(&mut self, v: OuterViewPort<dyn TerminalView>) {
let mut comp = self.view.write().unwrap();
let idx = comp.idx_count;
comp.idx_count += 1;
let layer = Arc::new(CompositeLayer {
comp: Arc::downgrade(&self.view),
idx: idx,
view: RwLock::new(None)
});
comp.layers.insert(idx, layer.clone());
drop(comp);
v.add_observer(layer);
} }
} }

View file

@ -7,6 +7,24 @@ pub use {
style::{TerminalStyle}, style::{TerminalStyle},
atom::{TerminalAtom}, atom::{TerminalAtom},
terminal::{Terminal, TerminalEvent}, terminal::{Terminal, TerminalEvent},
compositor::TerminalCompositor compositor::TerminalCompositor,
}; };
use {
crate::{
core::View,
view::{
IndexView,
GridView
}
},
cgmath::Point2,
std::ops::Range
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait TerminalView = GridView<Item = Option<TerminalAtom>>;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>

View file

@ -1,23 +1,40 @@
use { use {
std::io::{Write, stdout, stdin}, std::{
sync::{Arc, RwLock},
io::{Write, stdout, stdin},
collections::HashSet
},
async_std::{ async_std::{
stream::StreamExt, stream::StreamExt,
task task
}, },
signal_hook, signal_hook,
signal_hook_async_std::Signals, signal_hook_async_std::Signals,
cgmath::Vector2, cgmath::{Vector2, Point2},
termion::{ termion::{
raw::IntoRawMode, raw::IntoRawMode,
input::{TermRead, MouseTerminal} input::{TermRead, MouseTerminal}
}, },
super::{TerminalAtom, TerminalStyle},
crate::{ crate::{
view::{View, Observer}, core::{
port::{OuterViewPort}, OuterViewPort,
channel::ChannelReceiver Observer,
channel::{
ChannelReceiver,
ChannelSender,
queue_channel,
set_channel
} }
},
view::{
IndexView,
grid::GridWindowIterator
}
},
super::{
TerminalStyle,
TerminalView
},
}; };
pub enum TerminalEvent { pub enum TerminalEvent {
@ -26,36 +43,56 @@ pub enum TerminalEvent {
} }
pub struct Terminal { pub struct Terminal {
writer: Arc<TermOutWriter>,
observer: Arc<TermOutObserver>,
events: ChannelReceiver<Vec<TerminalEvent>>, events: ChannelReceiver<Vec<TerminalEvent>>,
signal_handle: signal_hook_async_std::Handle _signal_handle: signal_hook_async_std::Handle
} }
impl Terminal { impl Terminal {
pub fn new() -> Self { pub fn new(
let (event_tx, event_rx) = crate::channel::queue_channel(); port: OuterViewPort<dyn TerminalView>
) -> Self {
let (dirty_pos_tx, dirty_pos_rx) = set_channel();
let writer = Arc::new(TermOutWriter {
out: RwLock::new(MouseTerminal::from(stdout().into_raw_mode().unwrap())),
dirty_pos_rx,
view: port.get_view_arc()
});
let observer = Arc::new(TermOutObserver {
dirty_pos_tx,
writer: writer.clone()
});
port.add_observer(observer.clone());
let (event_tx, event_rx) = queue_channel();
let input_tx = event_tx.clone(); let input_tx = event_tx.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
for event in stdin().events() { for event in stdin().events() {
input_tx.notify(TerminalEvent::Input(event.unwrap())); input_tx.send(TerminalEvent::Input(event.unwrap()));
} }
}); });
// send initial teriminal size // send initial teriminal size
let (w,h) = termion::terminal_size().unwrap(); let (w, h) = termion::terminal_size().unwrap();
event_tx.notify(TerminalEvent::Resize(Vector2::new(w as i16, h as i16))); event_tx.send(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
// and again on SIGWINCH // and again on SIGWINCH
let signals = Signals::new(&[ signal_hook::SIGWINCH ]).unwrap(); let signals = Signals::new(&[ signal_hook::consts::signal::SIGWINCH ]).unwrap();
let handle = signals.handle(); let handle = signals.handle();
task::spawn(async move { task::spawn(async move {
let mut signals = signals.fuse(); let mut signals = signals.fuse();
while let Some(signal) = signals.next().await { while let Some(signal) = signals.next().await {
match signal { match signal {
signal_hook::SIGWINCH => { signal_hook::consts::signal::SIGWINCH => {
let (w,h) = termion::terminal_size().unwrap(); let (w,h) = termion::terminal_size().unwrap();
event_tx.notify(TerminalEvent::Resize(Vector2::new(w as i16, h as i16))); event_tx.send(TerminalEvent::Resize(Vector2::new(w as i16, h as i16)));
}, },
_ => unreachable!(), _ => unreachable!(),
} }
@ -63,42 +100,83 @@ impl Terminal {
}); });
Terminal { Terminal {
writer,
observer,
events: event_rx, events: event_rx,
signal_handle: handle _signal_handle: handle
} }
} }
pub fn get_writer(&self) -> Arc<TermOutWriter> {
self.writer.clone()
}
pub async fn next_event(&mut self) -> TerminalEvent { pub async fn next_event(&mut self) -> TerminalEvent {
self.events.next().await.unwrap() self.events.next().await.unwrap()
} }
}
pub async fn show(view_port: OuterViewPort<Vector2<i16>, TerminalAtom>) -> std::io::Result<()> { struct TermOutObserver {
let (atom_tx, atom_rx) = crate::channel::queue_channel(); dirty_pos_tx: ChannelSender<HashSet<Point2<i16>>>,
writer: Arc<TermOutWriter>
}
let view = view_port.get_view(); impl Observer<dyn TerminalView> for TermOutObserver {
view_port.add_observer_fn(move |pos| atom_tx.notify((pos, view.view(pos)))); fn reset(&self, view: Option<Arc<dyn TerminalView>>) {
self.writer.reset();
Self::show_stream(atom_rx).await let (w, h) = termion::terminal_size().unwrap();
if let Some(view) = view {
for pos in GridWindowIterator::from(
view.range().unwrap_or(
Point2::new(0, 0) .. Point2::new(w as i16, h as i16)
)
) {
self.dirty_pos_tx.send(pos);
}
}
} }
pub async fn show_stream(recv: ChannelReceiver<Vec<(Vector2<i16>, Option<TerminalAtom>)>>) -> std::io::Result<()> { fn notify(&self, pos: &Point2<i16>) {
let mut out = MouseTerminal::from(stdout().into_raw_mode().unwrap()); self.dirty_pos_tx.send(*pos);
let mut cur_pos = Vector2::<i16>::new(0, 0); }
let mut cur_style = TerminalStyle::default(); }
write!(out, "{}{}{}{}",
termion::clear::All, pub struct TermOutWriter {
termion::cursor::Goto(1, 1), out: RwLock<MouseTerminal<termion::raw::RawTerminal<std::io::Stdout>>>,
dirty_pos_rx: ChannelReceiver<HashSet<Point2<i16>>>,
view: Arc<RwLock<Option<Arc<dyn TerminalView>>>>
}
impl TermOutWriter {
fn reset(&self) {
let mut out = self.out.write().unwrap();
write!(out, "{}", termion::clear::All).ok();
}
}
impl TermOutWriter {
pub async fn show(&self) -> std::io::Result<()> {
// init
write!(self.out.write().unwrap(), "{}{}{}",
termion::cursor::Hide, termion::cursor::Hide,
termion::cursor::Goto(1, 1),
termion::style::Reset)?; termion::style::Reset)?;
while let Some(atoms) = recv.recv().await { let mut cur_pos = Point2::<i16>::new(0, 0);
for (pos, atom) in atoms.into_iter() { let mut cur_style = TerminalStyle::default();
if pos != cur_pos+Vector2::new(1,0) {
// draw atoms until view port is destroyed
while let Some(dirty_pos) = self.dirty_pos_rx.recv().await {
if let Some(view) = self.view.read().unwrap().as_ref() {
let mut out = self.out.write().unwrap();
for pos in dirty_pos.into_iter() {
if pos != cur_pos {
write!(out, "{}", termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1))?; write!(out, "{}", termion::cursor::Goto(pos.x as u16 + 1, pos.y as u16 + 1))?;
} }
cur_pos = pos;
if let Some(atom) = atom { if let Some(atom) = view.get(&pos) {
if cur_style != atom.style { if cur_style != atom.style {
cur_style = atom.style; cur_style = atom.style;
write!(out, "{}", atom.style)?; write!(out, "{}", atom.style)?;
@ -109,11 +187,16 @@ impl Terminal {
write!(out, "{} ", termion::style::Reset)?; write!(out, "{} ", termion::style::Reset)?;
cur_style = TerminalStyle::default(); cur_style = TerminalStyle::default();
} }
cur_pos = pos + Vector2::new(1, 0);
} }
out.flush()?; out.flush()?;
} }
}
// restore conventional terminal settings
let mut out = self.out.write().unwrap();
write!(out, "{}", termion::cursor::Show)?; write!(out, "{}", termion::cursor::Show)?;
out.flush()?; out.flush()?;

View file

@ -1,189 +0,0 @@
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait View : Send + Sync {
type Key;
type Value;
fn view(&self, key: Self::Key) -> Option<Self::Value>;
}
pub trait Observer : Send + Sync {
type Msg;
fn notify(&self, key: Self::Msg);
}
pub trait ObserverExt : Observer {
fn notify_each(&self, it: impl IntoIterator<Item = Self::Msg>);
}
impl<T: Observer> ObserverExt for T {
fn notify_each(&self, it: impl IntoIterator<Item = Self::Msg>) {
for msg in it {
self.notify(msg);
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use cgmath::Vector2;
pub trait SingletonView = View<Key = ()>;
pub trait SingletonObserver = Observer<Msg = ()>;
pub trait SequenceView = View<Key = usize>;
pub trait SequenceObserver = Observer<Msg = usize>;
pub trait GridView = View<Key = Vector2<i16>>;
pub trait GridObserver = Observer<Msg = Vector2<i16>>;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct FnView<K, V, F>
where K: Send + Sync,
V: Send + Sync,
F: Fn(K) -> Option<V> + Send + Sync {
f: F,
_phantom0: std::marker::PhantomData<K>,
_phantom1: std::marker::PhantomData<V>
}
impl<K, V, F> FnView<K, V, F>
where K: Send + Sync,
V: Send + Sync,
F: Fn(K) -> Option<V> + Send + Sync {
pub fn new(f: F) -> Self {
FnView {
f,
_phantom0: std::marker::PhantomData,
_phantom1: std::marker::PhantomData
}
}
}
impl<K, V, F> View for FnView<K, V, F>
where K: Send + Sync,
V: Send + Sync,
F: Fn(K) -> Option<V> + Send + Sync {
type Key = K;
type Value = V;
fn view(&self, key: K) -> Option<V> {
(self.f)(key)
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct FnObserver<T, F>
where T: Send + Sync,
F: Fn(T) + Send + Sync {
f: F,
_phantom: std::marker::PhantomData<T>
}
impl<T, F> FnObserver<T, F>
where T: Send + Sync,
F: Fn(T) + Send + Sync {
pub fn new(f: F) -> Self {
FnObserver {
f,
_phantom: std::marker::PhantomData
}
}
}
impl<T, F> Observer for FnObserver<T, F>
where T: Send + Sync,
F: Fn(T) + Send + Sync {
type Msg = T;
fn notify(&self, msg: T) {
(self.f)(msg);
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
use std::ops::Deref;
use std::sync::{Arc, RwLock};
impl<T: View> View for RwLock<T> {
type Key = T::Key;
type Value = T::Value;
fn view(&self, key: T::Key) -> Option<T::Value> {
self.read().unwrap().view(key)
}
}
impl<T: Observer> Observer for RwLock<T> {
type Msg = T::Msg;
fn notify(&self, msg: T::Msg) {
self.read().unwrap().notify(msg)
}
}
impl<T: View> View for Arc<T> {
type Key = T::Key;
type Value = T::Value;
fn view(&self, key: T::Key) -> Option<T::Value> {
self.deref().view(key)
}
}
impl<T: Observer> Observer for Arc<T> {
type Msg = T::Msg;
fn notify(&self, msg: T::Msg) {
self.deref().notify(msg)
}
}
impl<K, V> View for Arc<dyn View<Key = K, Value = V>>
where K: Send + Sync,
V: Send + Sync {
type Key = K;
type Value = V;
fn view(&self, key: K) -> Option<V> {
self.deref().view(key)
}
}
impl<T> Observer for Arc<dyn Observer<Msg = T>>
where T: Send + Sync {
type Msg = T;
fn notify(&self, msg: T) {
self.deref().notify(msg)
}
}
impl<T: View> View for Option<T> {
type Key = T::Key;
type Value = T::Value;
fn view(&self, key: T::Key) -> Option<T::Value> {
if let Some(view) = self.as_ref() {
view.view(key)
} else {
None
}
}
}
impl<T: Observer> Observer for Option<T> {
type Msg = T::Msg;
fn notify(&self, msg: T::Msg) {
if let Some(obs) = self.as_ref() {
obs.notify(msg);
}
}
}

78
src/view/grid.rs Normal file
View file

@ -0,0 +1,78 @@
use {
std::{
sync::{Arc, RwLock},
ops::{Deref, Range}
},
cgmath::{Point2, Vector2},
crate::{
core::View,
view::{IndexView, ImplIndexView}
}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait GridView = IndexView<Point2<i16>>;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/*
pub trait ImplGridView : Send + Sync {
type Item;
fn get(&self, pos: &Point2<i16>) -> Self::Item;
fn range(&self) -> Option<Range<Point2<i16>>> {
None
}
}
impl<V: ImplGridView> ImplIndexView for V {
type Key = Point2<i16>;
type Value = V::Item;
fn get(&self, pos: &Point2<i16>) -> V::Item {
(self as &V).get(pos)
}
fn range(&self) -> Option<Range<Point2<i16>>> {
(self as &V).range()
}
}
*/
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
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 Iterator for GridWindowIterator {
type Item = Point2<i16>;
fn next(&mut self) -> Option<Point2<i16>> {
if self.next.y < self.range.end.y {
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
}
}
}

73
src/view/index.rs Normal file
View file

@ -0,0 +1,73 @@
use {
std::{
sync::{Arc, RwLock},
ops::{Deref, Range}
},
crate::core::View
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait IndexView<Key> : View<Msg = Key> {
type Item;
fn get(&self, key: &Key) -> Self::Item;
fn range(&self) -> Option<Range<Key>> {
None
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<Key, V: IndexView<Key>> IndexView<Key> for RwLock<V> {
type Item = V::Item;
fn get(&self, key: &Key) -> Self::Item {
self.read().unwrap().get(key)
}
fn range(&self) -> Option<Range<Key>> {
self.read().unwrap().range()
}
}
impl<Key, V: IndexView<Key>> IndexView<Key> for Arc<V> {
type Item = V::Item;
fn get(&self, key: &Key) -> Self::Item {
self.deref().get(key)
}
fn range(&self) -> Option<Range<Key>> {
self.deref().range()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait ImplIndexView : Send + Sync {
type Key;
type Value;
fn get(&self, key: &Self::Key) -> Self::Value;
fn range(&self) -> Option<Range<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) -> Self::Item {
(self as &V).get(key)
}
fn range(&self) -> Option<Range<V::Key>> {
(self as &V).range()
}
}

13
src/view/mod.rs Normal file
View file

@ -0,0 +1,13 @@
pub mod singleton;
pub mod index;
pub mod sequence;
pub mod grid;
pub use {
singleton::SingletonView,
index::{IndexView, ImplIndexView},
sequence::SequenceView,
grid::GridView,
crate::core::View
};

41
src/view/sequence.rs Normal file
View file

@ -0,0 +1,41 @@
use {
std::{
sync::{Arc, RwLock},
ops::{Range, Deref}
},
super::{IndexView, ImplIndexView},
crate::core::View
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub trait SequenceView = IndexView<usize>;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/*
pub trait ImplSequenceView : Send + Sync {
type Item;
fn get(&self, idx: usize) -> Self::Item;
fn len(&self) -> Option<usize> {
None
}
}
impl<V: ImplSequenceView> ImplIndexView for V {
type Key = usize;
type Value = V::Item;
fn get(&self, idx: &usize) -> V::Item {
(self as V).get(*idx)
}
fn range(&self) -> Option<Range<usize>> {
if let Some(len) = (self as V).len() {
Some(0 .. len)
} else {
None
}
}
}
*/

53
src/view/singleton.rs Normal file
View file

@ -0,0 +1,53 @@
use {
std::{
sync::{Arc, RwLock},
ops::Deref
},
crate::core::{View}
};
// TODO: #[ImplForArc, ImplForRwLock]
pub trait SingletonView : View<Msg = ()> {
type Item;
fn get(&self) -> Self::Item;
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
impl<V: SingletonView> SingletonView for RwLock<V> {
type Item = V::Item;
fn get(&self) -> Self::Item {
self.read().unwrap().get()
}
}
impl<V: SingletonView> SingletonView for Arc<V> {
type Item = V::Item;
fn get(&self) -> Self::Item {
self.deref().get()
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
/*
pub trait ImplSingletonView : Send + Sync {
type Item;
fn get(&self) -> Self::Item;
}
impl<V: ImplSingletonView> View for V {
type Msg = ();
}
impl<V: ImplSingletonView> SingletonView for V {
type Item = V::Item;
fn get(&self) -> Self::Item {
(self as &V).get()
}
}
*/