use std::collections::HashMap;
use std::marker::PhantomData;
use std::cell::UnsafeCell;
use super::types::*;
use std::any::Any;
pub struct Runtime<E: Clone + Copy + 'static,> {
pub(crate) buffer_ids: Vec<Option<PhysicalBuffer>>,
pub(crate) buffers: HashMap<PhysicalBuffer, UnsafeCell<Vec<f32>>>,
pub(crate) buffer_size: usize,
pub(crate) execution_order: Vec<StoredComponent<E>>,
_event_type: PhantomData<E>,
update_rx: lockfree::channel::spsc::Receiver<Update<E>>,
event_rx: lockfree::channel::spsc::Receiver<(E)>,
pub(crate) system_buffers: SystemBuffers,
pub(crate) current_events: Vec<E>,
pub(crate) states: Vec<Box<UnsafeCell<dyn Any + Send + 'static>>>,
}
impl<E: Clone + Copy> Runtime<E> {
pub(crate) fn new(
update_rx: lockfree::channel::spsc::Receiver<Update<E>>,
event_rx: lockfree::channel::spsc::Receiver<E>,
states: Vec<Box<UnsafeCell<dyn Any + Send + 'static>>>,
buffer_size: usize,
) -> Self {
let mut buffers = HashMap::new();
buffers.insert(PhysicalBuffer(0), UnsafeCell::new(vec![0.0; buffer_size])); buffers.insert(PhysicalBuffer(1), UnsafeCell::new(vec![0.0; buffer_size]));
Self {
buffer_ids: Vec::new(),
buffers: buffers,
buffer_size: buffer_size,
execution_order: Vec::new(),
_event_type: PhantomData,
update_rx,
event_rx,
system_buffers: SystemBuffers{input: None, output: None},
current_events: Vec::new(),
states: states,
}
}
pub fn get_ctx(&self, handle: ContextHandle) -> Context<E> {
Context {
runtime: self,
handle,
buffer_size: self.buffer_size,
}
}
pub fn tick(&mut self) {
while let Ok(update) = self.update_rx.recv() {
(update.0)(self);
}
while let Ok((event)) = self.event_rx.recv() {
self.current_events.push(event)
}
for component in self.execution_order.iter(){
match component {
StoredComponent::User(UserComponent{component, context_handle, field_count, instance_name, processor_type}) => {
component(&self, *context_handle)
},
StoredComponent::System(SystemComponent{component_id, instance_name, buffer_idx}) => {
}
}
}
}
pub fn read_from(&mut self, input: &[f32]) {
let input_buf = if let Some(input_comp) = self.system_buffers.input {
self.buffer_ids[input_comp.buffer_idx.0].expect("fatal error: system buffer not allocated")
} else {
return
};
if let Some(buffer_cell) = self.buffers.get(&input_buf) {
unsafe {
let buffer = &mut *buffer_cell.get();
let copy_len = input.len().min(buffer.len());
buffer[..copy_len].copy_from_slice(&input[..copy_len]);
if copy_len < buffer.len() {
buffer[copy_len..].fill(0.0);
}
}
}
}
pub fn write_to(&self, output: &mut [f32]) {
let output_buf = if let Some(output_comp) = self.system_buffers.output {
self.buffer_ids[output_comp.buffer_idx.0].expect("fatal error: system buffer not allocated")
} else {
panic!("output buffer allocated incorrectly"); return
};
if let Some(buffer_cell) = self.buffers.get(&output_buf) {
unsafe {
let buffer = &*buffer_cell.get();
let copy_len = output.len().min(buffer.len());
output[..copy_len].copy_from_slice(&buffer[..copy_len]);
let has_signal = buffer.iter().any(|&x| x != 0.0);
if !has_signal {
println!("Warning: System output buffer is silent!");
}
if copy_len < output.len() {
output[copy_len..].fill(0.0);
}
}
} else {
println!("Warning: System output buffer not found!");
}
}
pub fn process(&mut self, input: Option<&[f32]>, output: &mut[f32]) {
if let Some(input) = input {
self.read_from(input);
};
self.tick();
self.write_to(output);
}
}
unsafe impl<E: Clone + Copy + 'static> Send for Runtime<E> {}
#[cfg(test)]
mod tests {
use super::*;
use std::any::Any;
use std::cell::UnsafeCell;
#[derive(Clone, Copy)]
struct TestEvent;
fn test_send<T: Send>() {}
#[test]
fn test_any_send() {
let _: Box<UnsafeCell<dyn Any + Send + 'static>> = Box::new(UnsafeCell::new(42i32));
let states: Vec<Box<UnsafeCell<dyn Any + Send + 'static>>> = vec![
Box::new(UnsafeCell::new(42i32)),
Box::new(UnsafeCell::new(String::from("test"))),
];
test_send::<Vec<Box<UnsafeCell<dyn Any + Send + 'static>>>>();
struct TestRuntime {
states: Vec<Box<UnsafeCell<dyn Any + Send + 'static>>>,
}
let test_runtime = TestRuntime { states };
test_send::<TestRuntime>();
println!("All Send tests passed!");
}
#[test]
fn test_runtime_send() {
test_send::<Runtime<TestEvent>>();
println!("Runtime Send test passed!");
}
}