diff --git a/copper/src/cutask.rs b/copper/src/cutask.rs index dcb6783d8..bb6dba02c 100644 --- a/copper/src/cutask.rs +++ b/copper/src/cutask.rs @@ -1,20 +1,30 @@ -use crate::config::NodeConfig; use serde::{Deserialize, Serialize}; -pub trait CuStateful<'a>: Default + Serialize + Deserialize<'a> {} +use crate::config::NodeConfig; + +// Everything that is stateful in copper for zero copy constraints need to be restricted to this trait. +pub trait CuMsg: Default + Serialize + for<'a> Deserialize<'a> + Sized {} -pub trait CuMsg<'a>: CuStateful<'a> {} +// Also anything that follows this contract can be a message +impl CuMsg for T where T: Default + Serialize + for<'a> Deserialize<'a> + Sized {} + +pub trait CuMsgLifecycle: Sync + Send + Clone + 'static { + type Msg: CuMsg; + + fn create(&self) -> &mut Self::Msg; + fn send(&self, msg: &Self::Msg); +} -pub trait CuSrcTask<'a, O>: CuStateful<'a> { - fn initialize(&self, config: NodeConfig, get_buffer: dyn Fn() -> &'a mut O, push_buffer: dyn Fn(&O)); +pub trait CuSrcTask> { + fn new(config: NodeConfig, msgif: L) -> Self; } -pub trait CuTask<'a, I,O>: CuStateful<'a> { - fn initialize(&self, config: NodeConfig); +pub trait CuTask { + fn new(config: NodeConfig) -> Self; fn process(&self, input: &I, output: &O) -> Result<(), String>; } -pub trait CuSinkTask<'a, I>: CuStateful<'a> { - fn initialize(&self, config: NodeConfig); +pub trait CuSinkTask { + fn new(&self, config: NodeConfig) -> Self; fn process(&self, input: &I) -> Result<(), String>; } diff --git a/copper/src/lib.rs b/copper/src/lib.rs index b8d22a80c..0d03cff67 100644 --- a/copper/src/lib.rs +++ b/copper/src/lib.rs @@ -1,2 +1,3 @@ pub mod config; pub mod cutask; +pub mod serde; diff --git a/copper/src/serde/arrays.rs b/copper/src/serde/arrays.rs new file mode 100644 index 000000000..75a5acec8 --- /dev/null +++ b/copper/src/serde/arrays.rs @@ -0,0 +1,66 @@ +use std::fmt; +use std::marker::PhantomData; + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde::de::{self, SeqAccess, Visitor}; +use serde::ser::SerializeSeq; + +pub fn serialize( + array: &[[T; WIDTH]; HEIGHT], + serializer: S, +) -> Result +where + S: Serializer, + T: Serialize, +{ + let mut seq = serializer.serialize_seq(Some(WIDTH * HEIGHT))?; + for row in array.iter() { + for element in row.iter() { + seq.serialize_element(element)?; + } + } + seq.end() +} + +pub fn deserialize<'de, D, T, const WIDTH: usize, const HEIGHT: usize>( + deserializer: D, +) -> Result<[[T; WIDTH]; HEIGHT], D::Error> +where + D: Deserializer<'de>, + T: Deserialize<'de> + Default + Copy, +{ + struct ArrayVisitor { + marker: PhantomData, + } + + impl<'de, T, const WIDTH: usize, const HEIGHT: usize> Visitor<'de> + for ArrayVisitor + where + T: Deserialize<'de> + Default + Copy, + { + type Value = [[T; WIDTH]; HEIGHT]; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a 2D array") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut array = [[T::default(); WIDTH]; HEIGHT]; + for row in array.iter_mut() { + for element in row.iter_mut() { + *element = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + } + } + Ok(array) + } + } + + deserializer.deserialize_seq(ArrayVisitor:: { + marker: PhantomData, + }) +} diff --git a/copper/src/serde/mod.rs b/copper/src/serde/mod.rs new file mode 100644 index 000000000..a8386d665 --- /dev/null +++ b/copper/src/serde/mod.rs @@ -0,0 +1 @@ +pub mod arrays; diff --git a/examples/camreader/Cargo.toml b/examples/camreader/Cargo.toml index fe91e74d8..02cefdc7d 100644 --- a/examples/camreader/Cargo.toml +++ b/examples/camreader/Cargo.toml @@ -7,3 +7,5 @@ edition = "2021" copper_plugin_type = "driver" [dependencies] +copper = { path = "../../copper" } +serde = { version = "1.0.201", features = ["derive"] } \ No newline at end of file diff --git a/examples/camreader/src/lib.rs b/examples/camreader/src/lib.rs index c3818a53a..b99f50620 100644 --- a/examples/camreader/src/lib.rs +++ b/examples/camreader/src/lib.rs @@ -1,28 +1,89 @@ +use std::thread; -struct CamReaderConfig { +use serde::{Deserialize, Serialize}; -} - -struct CamReader { +use copper::config::NodeConfig; +use copper::cutask::{CuMsg, CuMsgLifecycle, CuSrcTask}; +use copper::serde::arrays; +#[derive(Serialize, Deserialize)] +struct ImageBuffer { + #[serde(with = "arrays")] + buffer: [[u8; 1920]; 1200], } -pub fn build(config: CamReaderConfig) -> CamReader { - CamReader {} +impl Default for ImageBuffer { + fn default() -> Self { + ImageBuffer { + buffer: [[0; 1920]; 1200], + } + } } +// Concrete struct for CamReader. +struct CamReader> { + buff_management: L, +} -pub fn add(left: usize, right: usize) -> usize { - left + right +// Implement CuSrcTask for CamReader with a specific type (ImageBuffer). +impl> CuSrcTask for CamReader { + fn new(_config: NodeConfig, msgif: L) -> CamReader { + CamReader { + buff_management: msgif, + } + } } +impl> CamReader { + pub fn start(&self) { + let handle = thread::spawn({ + let buff_management = self.buff_management.clone(); + move || { + let mut i = 0; + loop { + let image = buff_management.create(); + image.buffer[0][0] = i; + i += 1; + buff_management.send(image); + } + } + }); + } +} + +// impl<'a> CuSrcTask<'a, ImageBuffer> for CamReader<'a> { +// fn new(_config: NodeConfig, msgif: dyn CuMsgLifecycle<'a, ImageBuffer>) -> CamReader<'a> { +// CamReader { +// buff_management: Box::new(msgif), +// } +// } +// } +// impl CamReader<'_, FB, FP> { +// pub fn run(&self) { +// let get_buffer = self.get_buffer.unwrap(); +// let push_buffer = self.push_buffer.unwrap(); +// +// // let get_buffer = Arc::new(Mutex::new(get_buffer)); +// // let push_buffer = Arc::new(Mutex::new(push_buffer)); +// +// // thread::spawn(move || { +// // let mut i = 0; +// // loop { +// // { +// // let get_buffer = get_buffer.lock().unwrap(); +// // let push_buffer = push_buffer.lock().unwrap(); +// // let buffer = get_buffer(); +// // buffer.buffer[0][0] = i; +// // i += 1; +// // push_buffer(buffer); +// // } +// // thread::sleep(Duration::from_secs(1)); +// // } +// // }); +// } +// } #[cfg(test)] mod tests { - use super::*; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } + fn it_works() {} }