first VecBuffer
This commit is contained in:
parent
589052977c
commit
28970658c0
4 changed files with 316 additions and 158 deletions
243
src/main.rs
243
src/main.rs
|
@ -7,7 +7,6 @@ pub mod grid;
|
||||||
pub mod sequence;
|
pub mod sequence;
|
||||||
pub mod singleton;
|
pub mod singleton;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
|
|
||||||
pub mod string_editor;
|
pub mod string_editor;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
@ -29,24 +28,162 @@ use {
|
||||||
Terminal,
|
Terminal,
|
||||||
TerminalCompositor
|
TerminalCompositor
|
||||||
},
|
},
|
||||||
grid::GridOffset
|
grid::{GridOffset, GridWindowIterator},
|
||||||
|
singleton::{SingletonView, SingletonBuffer}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VecSequenceView<T: Send + Sync + Clone>(Arc<RwLock<Vec<T>>>);
|
struct TermLabel(String);
|
||||||
impl<T: Send + Sync + Clone> ImplIndexView for VecSequenceView<T> {
|
impl ImplIndexView for TermLabel {
|
||||||
type Key = usize;
|
type Key = Point2<i16>;
|
||||||
type Value = T;
|
type Value = Option<TerminalAtom>;
|
||||||
|
|
||||||
fn get(&self, idx: &usize) -> T {
|
fn get(&self, pos: &Point2<i16>) -> Option<TerminalAtom> {
|
||||||
self.0.read().unwrap()[*idx].clone()
|
if pos.y == 5 {
|
||||||
|
Some(TerminalAtom::from(self.0.chars().nth(pos.x as usize)?))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn range(&self) -> Option<Range<usize>> {
|
fn area(&self) -> Option<Vec<Point2<i16>>> {
|
||||||
Some(0 .. self.0.read().unwrap().len())
|
Some(
|
||||||
|
GridWindowIterator::from(
|
||||||
|
Point2::new(0, 5) .. Point2::new(self.0.chars().count() as i16, 6)
|
||||||
|
).collect()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
#[async_std::main]
|
||||||
|
async fn main() {
|
||||||
|
let term_port = ViewPort::<dyn TerminalView>::new();
|
||||||
|
|
||||||
|
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 {
|
||||||
|
/*\
|
||||||
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
Setup Views
|
||||||
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
\*/
|
||||||
|
|
||||||
|
let window_size_port = ViewPort::new();
|
||||||
|
let window_size = SingletonBuffer::new(Vector2::new(0, 0), window_size_port.inner());
|
||||||
|
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
// string editor
|
||||||
|
let edit_port = ViewPort::<dyn TerminalView>::new();
|
||||||
|
let mut editor = string_editor::StringEditor::new(edit_port.inner());
|
||||||
|
|
||||||
|
compositor.push(edit_port.outer().map_key(
|
||||||
|
|pt| pt + Vector2::new(4, 2),
|
||||||
|
|pt| Some(pt - Vector2::new(4, 2))
|
||||||
|
));
|
||||||
|
|
||||||
|
let edit_offset_port = ViewPort::<dyn TerminalView>::new();
|
||||||
|
let edit_o = GridOffset::new(edit_offset_port.inner());
|
||||||
|
|
||||||
|
edit_port.add_observer(edit_o.clone());
|
||||||
|
|
||||||
|
compositor.push(
|
||||||
|
edit_offset_port
|
||||||
|
.into_outer()
|
||||||
|
// add a nice black background
|
||||||
|
.map_item(|atom| atom.map(
|
||||||
|
|a| a.add_style_back(TerminalStyle::bg_color((0,0,0)))))
|
||||||
|
);
|
||||||
|
|
||||||
|
edit_o.write().unwrap().set_offset(Vector2::new(40, 4));
|
||||||
|
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
// stupid label animation
|
||||||
|
let label_port = ViewPort::<dyn TerminalView>::new();
|
||||||
|
compositor.push(
|
||||||
|
label_port.outer()
|
||||||
|
.map_item(
|
||||||
|
|atom| atom.map(|atom|
|
||||||
|
atom.add_style_back(TerminalStyle::fg_color((255, 255, 255)))
|
||||||
|
.add_style_back(TerminalStyle::bg_color((0, 0, 0))))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
task::spawn(async move {
|
||||||
|
loop {
|
||||||
|
label_port.set_view(Some(Arc::new(TermLabel(String::from("Hello")))));
|
||||||
|
task::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
|
label_port.set_view(Some(Arc::new(TermLabel(String::from("I'm a dynamic label")))));
|
||||||
|
task::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
// Vec-Buffer
|
||||||
|
let vec_port = ViewPort::new();
|
||||||
|
let mut vec_buf = sequence::VecBuffer::<char>::new(vec_port.inner());
|
||||||
|
|
||||||
|
// project Vec-Buffer to SequenceView
|
||||||
|
let vec_seq_port = ViewPort::new();
|
||||||
|
let vec_seq = sequence::VecSequence::new(vec_seq_port.inner());
|
||||||
|
vec_port.add_observer(vec_seq.clone());
|
||||||
|
|
||||||
|
let vec_term_view = vec_seq_port.outer()
|
||||||
|
.to_index()
|
||||||
|
.map_key(
|
||||||
|
|idx: &usize| Point2::<i16>::new(*idx as i16, 0),
|
||||||
|
|pt: &Point2<i16>| if pt.y == 0 { Some(pt.x as usize) } else { None }
|
||||||
|
)
|
||||||
|
.map_item(
|
||||||
|
|c| Some(TerminalAtom::new(c.clone()?, TerminalStyle::fg_color((200, 10, 10))))
|
||||||
|
);
|
||||||
|
|
||||||
|
compositor.push(vec_term_view);
|
||||||
|
|
||||||
|
vec_buf.push('a');
|
||||||
|
vec_buf.push('b');
|
||||||
|
vec_buf.push('c');
|
||||||
|
|
||||||
|
/*\
|
||||||
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
Event Loop
|
||||||
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
\*/
|
||||||
|
loop {
|
||||||
|
match term.next_event().await {
|
||||||
|
TerminalEvent::Resize(size) => window_size.write().unwrap().set(size),
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Left)) => editor.prev(),
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Right)) => editor.next(),
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Home)) => editor.goto(0),
|
||||||
|
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); vec_buf.push(c); },
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Delete)) => editor.delete(),
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Backspace)) => { editor.prev(); editor.delete(); },
|
||||||
|
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*\
|
||||||
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
Terminal Rendering
|
||||||
|
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
\*/
|
||||||
|
term_writer.show().await.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
struct Checkerboard;
|
struct Checkerboard;
|
||||||
impl ImplIndexView for Checkerboard {
|
impl ImplIndexView for Checkerboard {
|
||||||
type Key = Point2<i16>;
|
type Key = Point2<i16>;
|
||||||
|
@ -66,11 +203,13 @@ impl ImplIndexView for Checkerboard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn range(&self) -> Option<Range<Point2<i16>>> {
|
fn area(&self) -> Option<Vec<Point2<i16>>> {
|
||||||
Some(Point2::new(0,0) .. Point2::new(20,10))
|
Some(GridWindowIterator::from(Point2::new(0,0) .. Point2::new(20,10)).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
struct ScrambleBackground;
|
struct ScrambleBackground;
|
||||||
impl ImplIndexView for ScrambleBackground {
|
impl ImplIndexView for ScrambleBackground {
|
||||||
type Key = Point2<i16>;
|
type Key = Point2<i16>;
|
||||||
|
@ -84,88 +223,10 @@ impl ImplIndexView for ScrambleBackground {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn range(&self) -> Option<Range<Point2<i16>>> {
|
fn area(&self) -> Option<Vec<Point2<i16>>> {
|
||||||
None
|
None
|
||||||
//Some(Point2::new(0,0) .. Point2::new(50,30))
|
//Some(Point2::new(0,0) .. Point2::new(50,30))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::main]
|
|
||||||
async fn main() {
|
|
||||||
let term_port = ViewPort::<dyn TerminalView>::new();
|
|
||||||
|
|
||||||
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 {
|
|
||||||
/*\
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
||||||
Setup Views
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
||||||
\*/
|
|
||||||
|
|
||||||
let offset_port = ViewPort::<dyn TerminalView>::new();
|
|
||||||
let o = GridOffset::new(offset_port.inner());
|
|
||||||
|
|
||||||
let checkerboard_port = ViewPort::<dyn TerminalView>::with_view(Arc::new(Checkerboard));
|
|
||||||
checkerboard_port.add_observer(o.clone());
|
|
||||||
|
|
||||||
compositor.push(offset_port.into_outer());
|
|
||||||
|
|
||||||
let edit_port = ViewPort::<dyn TerminalView>::new();
|
|
||||||
let mut editor = string_editor::StringEditor::new(edit_port.inner());
|
|
||||||
|
|
||||||
let edit_offset_port = ViewPort::<dyn TerminalView>::new();
|
|
||||||
let edit_o = GridOffset::new(edit_offset_port.inner());
|
|
||||||
edit_port.add_observer(edit_o.clone());
|
|
||||||
|
|
||||||
compositor.push(
|
|
||||||
edit_offset_port
|
|
||||||
.into_outer()
|
|
||||||
// add a nice black background
|
|
||||||
.map_item(|atom| atom.map(
|
|
||||||
|a| a.add_style_back(TerminalStyle::bg_color((0,0,0))))));
|
|
||||||
|
|
||||||
edit_o.write().unwrap().set_offset(Vector2::new(40, 4));
|
|
||||||
|
|
||||||
task::spawn(async move {
|
|
||||||
for x in 0 .. 20 {
|
|
||||||
async_std::task::sleep(std::time::Duration::from_millis(15)).await;
|
|
||||||
o.write().unwrap().set_offset(Vector2::new(x as i16, x as i16));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*\
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
||||||
Event Loop
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
||||||
\*/
|
|
||||||
loop {
|
|
||||||
match term.next_event().await {
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Left)) => editor.prev(),
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Right)) => editor.next(),
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Home)) => editor.goto(0),
|
|
||||||
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::Delete)) => editor.delete(),
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Backspace)) => { editor.prev(); editor.delete(); },
|
|
||||||
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*\
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
||||||
Terminal Rendering
|
|
||||||
<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
||||||
\*/
|
|
||||||
term_writer.show().await.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
162
src/sequence/vec_buffer.rs
Normal file
162
src/sequence/vec_buffer.rs
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
use {
|
||||||
|
std::{
|
||||||
|
sync::{Arc, RwLock}
|
||||||
|
},
|
||||||
|
crate::{
|
||||||
|
core::{View, Observer, ObserverExt, ObserverBroadcast, InnerViewPort},
|
||||||
|
sequence::SequenceView,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum VecDiff<T> {
|
||||||
|
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>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
pub struct VecSequence<T>
|
||||||
|
where T: Clone + Send + Sync + 'static {
|
||||||
|
cur_len: RwLock<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: RwLock::new(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.len().unwrap();
|
||||||
|
self.data = view;
|
||||||
|
let new_len = self.len().unwrap();
|
||||||
|
self.cast.notify_each(0 .. std::cmp::max(old_len, new_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notify(&self, diff: &VecDiff<T>) {
|
||||||
|
match diff {
|
||||||
|
VecDiff::Push(_) => {
|
||||||
|
let mut l = self.cur_len.write().unwrap();
|
||||||
|
self.cast.notify(&l);
|
||||||
|
*l += 1;
|
||||||
|
},
|
||||||
|
VecDiff::Remove(idx) => {
|
||||||
|
self.cast.notify(&idx);
|
||||||
|
*self.cur_len.write().unwrap() -= 1;
|
||||||
|
},
|
||||||
|
VecDiff::Insert{ idx, val } => {
|
||||||
|
let mut l = self.cur_len.write().unwrap();
|
||||||
|
*l += 1;
|
||||||
|
//self.cast.notify_each(idx .. &*l);
|
||||||
|
},
|
||||||
|
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) -> T {
|
||||||
|
self.data.as_ref().unwrap()
|
||||||
|
.read().unwrap()[idx].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> Option<usize> {
|
||||||
|
Some(*self.cur_len.read().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
||||||
|
|
||||||
|
pub struct VecBuffer<T>
|
||||||
|
where T: Clone + Send + Sync + 'static {
|
||||||
|
data: Arc<RwLock<Vec<T>>>,
|
||||||
|
cast: Arc<RwLock<ObserverBroadcast<RwLock<Vec<T>>>>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> VecBuffer<T>
|
||||||
|
where T: Clone + Send + Sync + 'static {
|
||||||
|
pub fn with_data(
|
||||||
|
data: Vec<T>,
|
||||||
|
port: InnerViewPort<RwLock<Vec<T>>>
|
||||||
|
) -> Self {
|
||||||
|
let data = Arc::new(RwLock::new(data));
|
||||||
|
port.set_view(Some(data.clone()));
|
||||||
|
VecBuffer { data, cast: port.get_broadcast() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(port: InnerViewPort<RwLock<Vec<T>>>) -> Self {
|
||||||
|
VecBuffer::with_data(Vec::new(), port)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_diff(&mut self, diff: VecDiff<T>) {
|
||||||
|
match diff {
|
||||||
|
VecDiff::Push(val) => self.push(val),
|
||||||
|
VecDiff::Remove(idx) => self.remove(idx),
|
||||||
|
VecDiff::Insert{ idx, val } => self.insert(idx, val),
|
||||||
|
VecDiff::Update{ idx, val } => self.update(idx, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 push(&mut self, val: T) {
|
||||||
|
self.data.write().unwrap().push(val.clone());
|
||||||
|
self.cast.notify(&VecDiff::Push(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, idx: usize) {
|
||||||
|
self.data.write().unwrap().remove(idx);
|
||||||
|
self.cast.notify(&VecDiff::Remove(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, idx: usize, val: T) {
|
||||||
|
self.data.write().unwrap().insert(idx, val.clone());
|
||||||
|
self.cast.notify(&VecDiff::Insert{ idx, val });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, idx: usize, val: T) {
|
||||||
|
self.data.write().unwrap()[idx] = val.clone();
|
||||||
|
self.cast.notify(&VecDiff::Update{ idx, val });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ use {
|
||||||
crate::core::{View}
|
crate::core::{View}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use buffer::SingletonBuffer;
|
||||||
|
|
||||||
// TODO: #[ImplForArc, ImplForRwLock]
|
// TODO: #[ImplForArc, ImplForRwLock]
|
||||||
pub trait SingletonView : View<Msg = ()> {
|
pub trait SingletonView : View<Msg = ()> {
|
||||||
type Item;
|
type Item;
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
use {
|
|
||||||
std::{
|
|
||||||
sync::{Arc, RwLock}
|
|
||||||
},
|
|
||||||
crate::{
|
|
||||||
view::{View, Observer},
|
|
||||||
port::{InnerViewPort}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
impl<T: Clone + Send + Sync> View for Vec<T> {
|
|
||||||
type Key = usize;
|
|
||||||
type Value = T;
|
|
||||||
|
|
||||||
fn view(&self, key: usize) -> Option<T> {
|
|
||||||
self.get(key).cloned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VecBuffer<T: Clone + Eq + Send + Sync + 'static> {
|
|
||||||
data: Arc<RwLock<Vec<T>>>,
|
|
||||||
port: InnerViewPort<usize, T>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone + Eq + Send + Sync + 'static> VecBuffer<T> {
|
|
||||||
pub fn new(port: InnerViewPort<usize, T>) -> Self {
|
|
||||||
let data = Arc::new(RwLock::new(Vec::new()));
|
|
||||||
port.set_view(data.clone());
|
|
||||||
VecBuffer { data, port }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, val: T) {
|
|
||||||
self.port.notify({
|
|
||||||
let mut d = self.data.write().unwrap();
|
|
||||||
let idx = d.len();
|
|
||||||
d.push(val);
|
|
||||||
idx
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove(&mut self, idx: usize) {
|
|
||||||
let len = {
|
|
||||||
let mut d = self.data.write().unwrap();
|
|
||||||
let len = d.len();
|
|
||||||
d.remove(idx);
|
|
||||||
len
|
|
||||||
};
|
|
||||||
|
|
||||||
for i in idx .. len {
|
|
||||||
self.port.notify(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, idx: usize, val: T) {
|
|
||||||
let len = {
|
|
||||||
let mut d = self.data.write().unwrap();
|
|
||||||
d.insert(idx, val);
|
|
||||||
let len = d.len();
|
|
||||||
len
|
|
||||||
};
|
|
||||||
|
|
||||||
for i in idx .. len {
|
|
||||||
self.port.notify(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue