use std::fmt;
use bytemuck::bytes_of;
use contracts::requires;
use crate::util::BytesExt;
use super::{
NgPayload,
common::{
ByteFold, CRC, Command, FrameOld, MixShim, NgPayloadInternal, NgShim, SZ_ARGS, SZ_DATA,
},
};
pub type RequestOld = FrameOld;
pub type RequestMix = RequestNgFrame<MixShim>;
pub type RequestNg = RequestNgFrame<NgShim>;
#[derive(Debug, Copy, Clone)]
pub struct RequestNgFrame<D> {
cmd: Command,
shim: D,
}
#[requires(payload.as_ref().len() <= SZ_DATA, "payload size exceeds frame capabilities")]
pub fn old(cmd: Command, args: [u64; 3], payload: impl AsRef<[u8]>) -> RequestOld {
RequestOld {
cmd,
args,
payload: payload.as_ref().to_buffer(),
}
}
#[requires(payload.as_ref().len() <= SZ_DATA - SZ_ARGS, "payload size exceeds frame capabilities")]
pub fn mix(cmd: Command, args: [u64; 3], payload: impl AsRef<[u8]>) -> RequestMix {
let payload = payload.as_ref();
RequestMix {
cmd,
shim: MixShim {
args,
len: payload.len(),
buf: payload.to_buffer(),
},
}
}
#[requires(payload.as_ref().len() <= SZ_DATA, "payload size exceeds frame capabilities")]
pub fn ng(cmd: Command, payload: impl AsRef<[u8]>) -> RequestNg {
let payload = payload.as_ref();
RequestNg {
cmd,
shim: NgShim {
len: payload.len(),
buf: payload.to_buffer(),
},
}
}
#[allow(private_bounds)]
pub trait Request: ByteFold + fmt::Debug + Copy + Clone {
fn cmd(&self) -> Command;
fn payload(&self) -> &[u8];
}
impl Request for RequestOld {
fn cmd(&self) -> Command {
self.cmd
}
fn payload(&self) -> &[u8] {
&self.payload
}
}
impl<S: NgPayload + NgPayloadInternal> Request for RequestNgFrame<S> {
fn cmd(&self) -> Command {
self.cmd
}
fn payload(&self) -> &[u8] {
self.shim.payload()
}
}
const NG_REQUEST_MAGIC: u32 = 0x61_33_4d_50;
const NG_REQUEST_CRC_FALLBACK: u16 = 0x33_61;
pub(crate) const SZ_BUF: usize = size_of_val(&NG_REQUEST_MAGIC) + 3 * size_of::<u16>() + SZ_DATA;
impl<D: NgPayloadInternal> ByteFold for RequestNgFrame<D> {
fn try_byte_fold<F, E>(&self, mut f: F) -> Result<(), E>
where
F: FnMut(&[u8]) -> Result<(), E>,
{
let mut digest = CRC.digest();
let mut g = |x| {
f(x)?;
digest.update(x);
Ok(())
};
let ng_length = self.shim.ng_length().into_bits();
g(bytes_of(&NG_REQUEST_MAGIC))?;
g(bytes_of(&ng_length))?;
g(bytes_of(&self.cmd))?;
self.shim.try_byte_fold(|x| {
f(x)?;
digest.update(x);
Ok(())
})?;
f(bytes_of(&NG_REQUEST_CRC_FALLBACK))?;
Ok(())
}
}