use super::{TransmissionValue, Value};
use crate::executive::SendResult;
use async_trait::async_trait;
use core::fmt::Debug;
pub trait Outputs: Debug + Send + Sync {
fn get(&mut self, output: &str) -> Box<dyn Output>;
}
#[async_trait]
pub trait Output: Debug + Send + Sync {
async fn close(&self);
async fn send_many(&self, data: TransmissionValue) -> SendResult;
async fn send_one(&self, data: Value) -> SendResult;
async fn force_send(&self);
}
#[async_trait]
pub trait OutputExt: Output {
async fn send_one_as<T: Into<Value> + Send>(&self, value: T) -> SendResult {
self.send_one(value.into()).await
}
async fn send_many_as<T: Send>(&self, values: Vec<T>) -> SendResult
where
TransmissionValue: From<Vec<T>>,
{
self.send_many(values.into()).await
}
}
impl<O: Output + ?Sized> OutputExt for O {}
#[cfg(test)]
mod output_ext_tests {
use super::*;
use crate::executive::PackedArray;
use async_std::sync::Mutex;
use std::convert::TryInto;
#[derive(Debug)]
struct FakeOutput {
sent_one: Mutex<Option<Value>>,
sent_many: Mutex<Option<TransmissionValue>>,
}
fn fake_output() -> FakeOutput {
FakeOutput {
sent_one: Mutex::new(None),
sent_many: Mutex::new(None),
}
}
#[async_trait]
impl Output for FakeOutput {
async fn close(&self) {}
async fn send_many(&self, data: TransmissionValue) -> SendResult {
*self.sent_many.lock().await = Some(data);
Ok(())
}
async fn send_one(&self, data: Value) -> SendResult {
*self.sent_one.lock().await = Some(data);
Ok(())
}
async fn force_send(&self) {}
}
#[test]
fn send_one_as_converts_through_into_value() {
async_std::task::block_on(async {
let output = fake_output();
output.send_one_as::<u64>(42).await.unwrap();
assert_eq!(output.sent_one.lock().await.take(), Some(Value::U64(42)));
});
}
#[test]
fn send_many_as_sends_a_batch_of_scalar_ticks() {
async_std::task::block_on(async {
let output = fake_output();
output.send_many_as(vec![1u8, 2, 3]).await.unwrap();
let sent = output.sent_many.lock().await.take().unwrap();
assert!(matches!(sent, TransmissionValue::U8(_)));
let back: Vec<u8> = sent.try_into().unwrap();
assert_eq!(back, vec![1, 2, 3]);
});
}
#[test]
fn send_one_as_auto_packs_a_vec_of_a_packable_type() {
async_std::task::block_on(async {
let output = fake_output();
output.send_one_as(vec![1u8, 2, 3]).await.unwrap();
assert!(matches!(
output.sent_one.lock().await.take(),
Some(Value::Packed(PackedArray::U8(_)))
));
});
}
#[test]
fn send_many_as_packed_arrays_sends_a_batch_of_arrays() {
async_std::task::block_on(async {
let output = fake_output();
output
.send_many_as(vec![
std::sync::Arc::new(vec![1u8, 2, 3]),
std::sync::Arc::new(vec![4u8, 5]),
])
.await
.unwrap();
let sent = output.sent_many.lock().await.take().unwrap();
assert!(matches!(sent, TransmissionValue::PackedU8(_)));
assert_eq!(sent.len(), 2);
});
}
#[test]
fn send_many_as_still_works_for_a_non_packable_type() {
async_std::task::block_on(async {
let output = fake_output();
output
.send_many_as(vec!["a".to_string(), "b".to_string()])
.await
.unwrap();
let sent = output.sent_many.lock().await.take().unwrap();
assert!(matches!(sent, TransmissionValue::String(_)));
});
}
#[test]
fn send_one_as_packed_array_produces_value_packed() {
async_std::task::block_on(async {
let output = fake_output();
let arr = PackedArray::Byte(std::sync::Arc::new(vec![1u8, 2, 3]));
output.send_one_as(arr).await.unwrap();
assert!(matches!(
output.sent_one.lock().await.take(),
Some(Value::Packed(PackedArray::Byte(_)))
));
});
}
}