crate::ix!();
#[derive(Builder,MutGetters,Setters,Getters,Debug,Clone)]
#[builder(setter(into))]
#[getset(get="pub",set = "pub", get_mut = "pub")]
pub struct NetworkNode<NetworkItem>
where NetworkItem: Debug + Send + Sync
{
index: usize,
operator: Arc<dyn Operator<NetworkItem>>,
inputs: NetworkNodeIoChannelArray<NetworkItem>,
outputs: NetworkNodeIoChannelArray<NetworkItem>,
}
impl<NetworkItem> NetworkNode<NetworkItem>
where NetworkItem: Debug + Send + Sync
{
pub async fn execute(&self) -> NetResult<()> {
let mut read_guards: NetworkNodeIoChannelReadGuardArray<'_, NetworkItem>
= [None, None, None, None];
for i in 0..4 {
if let Some(arc) = &self.inputs[i] {
read_guards[i] = Some(arc.read().await);
}
}
let inputs: [Option<&NetworkItem>; 4] = [
read_guards[0].as_ref().map(|g| &**g),
read_guards[1].as_ref().map(|g| &**g),
read_guards[2].as_ref().map(|g| &**g),
read_guards[3].as_ref().map(|g| &**g),
];
let mut output_buffer: NetworkNodeIoChannelValues<NetworkItem> =
[None, None, None, None];
self.operator.execute(inputs, &mut output_buffer).await?;
let mut write_guards: [Option<tokio::sync::RwLockWriteGuard<'_, NetworkItem>>; 4]
= [None, None, None, None];
for i in 0..4 {
if let Some(arc) = &self.outputs[i] {
write_guards[i] = Some(arc.write().await);
}
}
Self::finish_execution(write_guards, output_buffer)?;
Ok(())
}
fn finish_execution(mut output: NetworkNodeIoChannelWriteGuardArray<'_,NetworkItem>, mut values: NetworkNodeIoChannelValues<NetworkItem>) -> NetResult<()>
where NetworkItem: Debug + Send + Sync
{
if let Some(o0) = &mut output[0] { if let Some(v) = values[0].take() { **o0 = v; } }
if let Some(o1) = &mut output[1] { if let Some(v) = values[1].take() { **o1 = v; } }
if let Some(o2) = &mut output[2] { if let Some(v) = values[2].take() { **o2 = v; } }
if let Some(o3) = &mut output[3] { if let Some(v) = values[3].take() { **o3 = v; } }
Ok(())
}
}
#[macro_export]
macro_rules! node {
($idx:expr => $op:expr) => {
NetworkNodeBuilder::default()
.index($idx as usize)
.operator($op.into_arc_operator())
.inputs([None, None, None, None])
.outputs([None, None, None, None])
.build()
.unwrap()
};
}
#[cfg(test)]
mod node_macro_tests {
use super::*;
#[test]
fn test_node_macro_single_noop() {
let n0: NetworkNode<TestWireIO<i32>> = node!(0 => NoOpOperator::default());
assert_eq!(*n0.index(), 0);
assert_eq!(n0.operator().name(), "default");
for i in 0..4 {
assert!(n0.inputs()[i].is_none(), "Expected no inputs yet");
assert!(n0.outputs()[i].is_none(), "Expected no outputs yet");
}
}
#[test]
fn test_node_macro_with_custom_operator() {
let n7: NetworkNode<TestWireIO<i32>> = node!(7 => AddOp::new(7));
assert_eq!(*n7.index(), 7);
assert_eq!(n7.operator().name(), "AddOp(+7)");
for i in 0..4 {
assert!(n7.inputs()[i].is_none());
assert!(n7.outputs()[i].is_none());
}
}
}