use super::Backend;
use crate::{CopyToSlice, Error, Instruction, StatusCode};
const MAX_SIZE: usize = 59;
pub async fn plain<'a, BackendT>(
backend: &BackendT,
output: &'a mut [u8],
input: &[u8],
) -> Result<(StatusCode, &'a [u8]), Error<BackendT::Error>>
where
BackendT: Backend,
BackendT::Error: crate::std::fmt::Debug,
{
plain_multi(backend, output, input, &[]).await
}
pub async fn plain_multi<'a, BackendT>(
backend: &BackendT,
output: &'a mut [u8],
header: &[u8],
data: &[&[u8]],
) -> Result<(StatusCode, &'a [u8]), Error<BackendT::Error>>
where
BackendT: Backend,
BackendT::Error: crate::std::fmt::Debug,
{
let (mut data, data_len) = {
let data_len = data.iter().fold(0, |n, data| n + data.len());
(data.iter().flat_map(|v| v.iter()), data_len)
};
let mut command = header;
let mut buf_in = [0; 0xff]; let mut buf_out = [0; 0xff]; let mut n = 0;
let mut n_out = 0;
loop {
let (status_code, response) = backend
.exchange(&mut buf_out, command)
.await
.map_err(Error::IoBackend)?;
output[n..(n + response.len())].copy_from_slice(response);
n += response.len();
match status_code {
StatusCode::AdditionalData => {
buf_in[0] = Instruction::AdditionalData as u8;
if let Some(n) = (&mut data)
.take(MAX_SIZE)
.copied()
.copy_to_slice(&mut buf_in[1..])
{
command = &buf_in[..(n + 1)];
n_out += n;
} else {
command = &buf_in[..1];
}
continue;
}
_ => {
if n_out != data_len {
return Err(Error::IncompleteWrite);
}
return Ok((status_code, &output[..n]));
}
}
}
}
#[cfg(test)]
mod tests {
use super::super::MockBackend;
use super::*;
#[tokio::test]
async fn test_plain() {
let mb = MockBackend::new(&[(&[0xFF], b"\xAFHello, "), (&[0xAF], b"\x00World!")]);
let mut out = [0; 0xff];
let (status_code, response) = plain(&mb, &mut out, &[0xFF]).await.unwrap();
assert_eq!(StatusCode::Ack, status_code);
assert_eq!(b"Hello, World!", &response);
}
}