use crate::{Rc, Signal};
#[cfg(not(feature = "std"))]
type BTreeMap<K, V> = alloc::collections::btree_map::BTreeMap<K, V>;
#[cfg(feature = "std")]
type BTreeMap<K, V> = std::collections::BTreeMap<K, V>;
#[cfg(not(feature = "std"))]
type VecDeque<T> = alloc::collections::vec_deque::VecDeque<T>;
#[cfg(feature = "std")]
type VecDeque<T> = std::collections::vec_deque::VecDeque<T>;
pub trait SignalBus: Signal {
fn bus(self) -> Bus<Self>
where
Self: Sized,
{
Bus::new(self, BTreeMap::new())
}
}
struct SharedNode<S>
where
S: Signal,
{
signal: S,
buffer: VecDeque<S::Frame>,
frames_read: BTreeMap<usize, usize>,
next_key: usize,
}
pub struct Bus<S>
where
S: Signal,
{
node: Rc<core::cell::RefCell<SharedNode<S>>>,
}
pub struct Output<S>
where
S: Signal,
{
key: usize,
node: Rc<core::cell::RefCell<SharedNode<S>>>,
}
impl<S> Bus<S>
where
S: Signal,
{
fn new(signal: S, frames_read: BTreeMap<usize, usize>) -> Self {
Bus {
node: Rc::new(core::cell::RefCell::new(SharedNode {
signal: signal,
buffer: VecDeque::new(),
frames_read: frames_read,
next_key: 0,
})),
}
}
#[inline]
pub fn send(&self) -> Output<S> {
let mut node = self.node.borrow_mut();
let key = node.next_key;
node.next_key = node.next_key.wrapping_add(1);
let num_frames = node.buffer.len();
node.frames_read.insert(key, num_frames);
Output {
key: key,
node: self.node.clone(),
}
}
}
impl<S> SharedNode<S>
where
S: Signal,
{
fn next_frame(&mut self, key: usize) -> S::Frame {
let num_frames = self.buffer.len();
let frames_read = self
.frames_read
.remove(&key)
.expect("no frames_read for Output");
let frame = if frames_read < num_frames {
self.buffer[frames_read]
} else {
let frame = self.signal.next();
self.buffer.push_back(frame);
frame
};
let least_frames_read = !self
.frames_read
.values()
.any(|&other_frames_read| other_frames_read <= frames_read);
let new_frames_read = if least_frames_read {
self.buffer.pop_front();
for other_frames_read in self.frames_read.values_mut() {
*other_frames_read -= 1;
}
frames_read
} else {
frames_read + 1
};
self.frames_read.insert(key, new_frames_read);
frame
}
#[inline]
fn pending_frames(&self, key: usize) -> usize {
self.buffer.len() - self.frames_read[&key]
}
fn drop_output(&mut self, key: usize) {
self.frames_read.remove(&key);
let least_frames_read = self
.frames_read
.values()
.fold(self.buffer.len(), |a, &b| core::cmp::min(a, b));
if least_frames_read > 0 {
for frames_read in self.frames_read.values_mut() {
*frames_read -= least_frames_read;
}
for _ in 0..least_frames_read {
self.buffer.pop_front();
}
}
}
}
impl<S> Output<S>
where
S: Signal,
{
#[inline]
pub fn pending_frames(&self) -> usize {
self.node.borrow().pending_frames(self.key)
}
}
impl<T> SignalBus for T where T: Signal {}
impl<S> Signal for Output<S>
where
S: Signal,
{
type Frame = S::Frame;
#[inline]
fn next(&mut self) -> Self::Frame {
self.node.borrow_mut().next_frame(self.key)
}
#[inline]
fn is_exhausted(&self) -> bool {
let node = self.node.borrow();
node.pending_frames(self.key) == 0 && node.signal.is_exhausted()
}
}
impl<S> Drop for Output<S>
where
S: Signal,
{
fn drop(&mut self) {
self.node.borrow_mut().drop_output(self.key)
}
}