use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use crate::math::Scalar;
pub type IoResult<T> = Result<T, String>;
pub trait IoControl {
fn write_data(&self, data: &[u8]) -> usize;
}
pub trait IoBackend<T: Scalar> {
fn set_process_callback(&self, cb: Box<dyn Fn(f32)>);
fn read(&self, channels: &mut [&mut [T]]) -> usize;
fn write(&self, channels: &[&[T]]) -> usize;
fn run(&self, running: Arc<AtomicBool>) -> IoResult<()>;
fn stop(&self) -> IoResult<()>;
fn as_control(&self) -> Option<&dyn IoControl> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::sync::Arc;
struct TestBackend {
reg: AtomicU8,
}
impl IoBackend<f32> for TestBackend {
fn set_process_callback(&self, _cb: Box<dyn Fn(f32)>) {}
fn read(&self, _: &mut [&mut [f32]]) -> usize {
0
}
fn write(&self, _: &[&[f32]]) -> usize {
0
}
fn run(&self, _: Arc<AtomicBool>) -> IoResult<()> {
Ok(())
}
fn stop(&self) -> IoResult<()> {
Ok(())
}
fn as_control(&self) -> Option<&dyn IoControl> {
Some(self)
}
}
impl IoControl for TestBackend {
fn write_data(&self, data: &[u8]) -> usize {
if let Some(&v) = data.first() {
self.reg.store(v, Ordering::Relaxed);
}
1
}
}
#[test]
fn test_iocontrol_write_data() {
let b = TestBackend {
reg: AtomicU8::new(0),
};
let ctrl = b.as_control().unwrap();
ctrl.write_data(&[42]);
assert_eq!(b.reg.load(Ordering::Relaxed), 42);
}
#[test]
fn test_iocontrol_default_returns_none() {
struct NoControl;
impl IoBackend<f32> for NoControl {
fn set_process_callback(&self, _cb: Box<dyn Fn(f32)>) {}
fn read(&self, _: &mut [&mut [f32]]) -> usize {
0
}
fn write(&self, _: &[&[f32]]) -> usize {
0
}
fn run(&self, _: Arc<AtomicBool>) -> IoResult<()> {
Ok(())
}
fn stop(&self) -> IoResult<()> {
Ok(())
}
}
let b = NoControl;
assert!(b.as_control().is_none());
}
}