use std::{
collections::VecDeque,
sync::{Arc, Mutex},
time::Duration,
};
use crate::error::{EmapiError, Result};
pub trait EmapiConnection {
fn write(&mut self, data: &[u8]) -> Result<()>;
fn read(&mut self, timeout: Duration) -> Result<Vec<u8>>;
}
#[derive(Debug, Clone)]
pub struct ScriptedEmapiConnection {
state: Arc<Mutex<ScriptedEmapiConnectionState>>,
}
#[derive(Debug, Default)]
struct ScriptedEmapiConnectionState {
responses: VecDeque<Option<Vec<u8>>>,
writes: Vec<Vec<u8>>,
reads: usize,
}
impl ScriptedEmapiConnection {
pub fn new(responses: Vec<Option<Vec<u8>>>) -> Self {
Self {
state: Arc::new(Mutex::new(ScriptedEmapiConnectionState {
responses: responses.into(),
writes: Vec::new(),
reads: 0,
})),
}
}
pub fn writes(&self) -> Vec<Vec<u8>> {
self.state.lock().unwrap().writes.clone()
}
pub fn reads(&self) -> usize {
self.state.lock().unwrap().reads
}
}
impl EmapiConnection for ScriptedEmapiConnection {
fn write(&mut self, data: &[u8]) -> Result<()> {
self.state.lock().unwrap().writes.push(data.to_vec());
Ok(())
}
fn read(&mut self, timeout: Duration) -> Result<Vec<u8>> {
let mut state = self.state.lock().unwrap();
state.reads += 1;
match state.responses.pop_front() {
Some(Some(response)) => Ok(response),
Some(None) => Err(EmapiError::Timeout {
message: format!("timeout waiting for response after {timeout:?}"),
}),
None => Err(EmapiError::Timeout {
message: format!("no response after {timeout:?}"),
}),
}
}
}