use core::fmt;
use core::marker::PhantomData;
use core::ops::Range;
use channels_io::buf::{Buf, Chain, Cursor};
use crate::flags::Flags;
use crate::header::{Header, HeaderBytes, HeaderError};
use crate::payload::Payload;
use crate::seq::{FrameNum, FrameNumSequence};
use crate::util::Error;
use crate::wants::Wants;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Frame<T> {
pub flags: Flags,
pub frame_num: FrameNum,
pub payload: T,
}
impl<T> Frame<T> {
#[inline]
pub const fn builder() -> Builder<T> {
Builder::new()
}
#[inline]
pub fn map_payload<U, F>(self, f: F) -> Frame<U>
where
F: FnOnce(T) -> U,
{
Frame {
flags: self.flags,
frame_num: self.frame_num,
payload: f(self.payload),
}
}
fn get_header(&self, data_len: u32) -> Header {
Header {
flags: self.flags,
frame_num: self.frame_num,
data_len,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FrameError {
Header(HeaderError),
TooLarge,
}
impl fmt::Display for FrameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Header(e) => e.fmt(f),
Self::TooLarge => f.write_str("frame too large"),
}
}
}
impl Error for FrameError {}
impl Frame<Range<usize>> {
pub fn try_parse_range(
bytes: &[u8],
) -> Result<Result<Self, Wants>, FrameError> {
let header = match Header::try_parse(bytes) {
Ok(Ok(x)) => x,
Ok(Err(wants)) => return Ok(Err(wants)),
Err(e) => return Err(FrameError::Header(e)),
};
let data_len = header
.data_len
.try_into()
.map_err(|_| FrameError::TooLarge)?;
let frame_len = Header::SIZE
.checked_add(data_len)
.ok_or(FrameError::TooLarge)?;
if bytes.len() < frame_len {
return Ok(Err(Wants(frame_len - bytes.len())));
}
Ok(Ok(Frame {
flags: header.flags,
frame_num: header.frame_num,
payload: Header::SIZE..frame_len,
}))
}
#[inline]
#[must_use]
pub fn length(&self) -> Option<usize> {
calculate_frame_len(self.payload.len())
}
#[inline]
#[must_use]
pub fn header(&self) -> Option<Header> {
let len = self.payload.len().try_into().ok()?;
Some(self.get_header(len))
}
}
impl<'a> Frame<Payload<&'a [u8]>> {
#[allow(clippy::missing_panics_doc)]
pub fn try_parse(
bytes: &'a [u8],
) -> Result<Result<Self, Wants>, FrameError> {
let frame = match Frame::try_parse_range(bytes) {
Ok(Ok(x)) => x,
Ok(Err(wants)) => return Ok(Err(wants)),
Err(e) => return Err(e),
};
Ok(Ok(frame.map_payload(|x| {
Payload::new(&bytes[x]).expect(
"try_parse_range returned an invalid payload range",
)
})))
}
}
impl<T: AsRef<[u8]>> Frame<Payload<T>> {
#[inline]
#[must_use]
pub fn length(&self) -> Option<usize> {
calculate_frame_len(self.payload.get().as_ref().len())
}
#[inline]
#[must_use]
pub fn header(&self) -> Header {
self.get_header(self.payload.length())
}
#[inline]
#[must_use]
pub fn encode(self) -> EncodedFrame<T> {
EncodedFrame::new(self)
}
}
impl<T> Frame<Payload<T>> {
#[inline]
#[must_use]
pub fn as_ref(&self) -> Frame<Payload<&T>> {
Frame {
flags: self.flags,
frame_num: self.frame_num,
payload: self.payload.as_ref(),
}
}
#[inline]
#[must_use]
pub fn as_mut(&mut self) -> Frame<Payload<&mut T>> {
Frame {
flags: self.flags,
frame_num: self.frame_num,
payload: self.payload.as_mut(),
}
}
}
#[derive(Debug, Clone)]
pub struct EncodedFrame<T> {
inner: Chain<Cursor<HeaderBytes>, Cursor<T>>,
}
impl<T> EncodedFrame<T>
where
T: AsRef<[u8]>,
{
#[inline]
fn new(frame: Frame<Payload<T>>) -> Self {
let header = Cursor::new(frame.header().to_bytes());
let payload = Cursor::new(frame.payload.into_inner());
Self { inner: Buf::chain(header, payload) }
}
}
impl<T: AsRef<[u8]>> Buf for EncodedFrame<T> {
fn remaining(&self) -> usize {
self.inner.remaining()
}
fn chunk(&self) -> &[u8] {
self.inner.chunk()
}
fn advance(&mut self, n: usize) {
self.inner.advance(n);
}
}
#[allow(missing_debug_implementations)]
#[must_use = "builders don't do anything unless you build them"]
pub struct Builder<T> {
_marker: PhantomData<T>,
flags: Flags,
frame_num: FrameNum,
}
impl<T> Builder<T> {
#[inline]
pub const fn new() -> Self {
Self {
_marker: PhantomData,
flags: Flags::empty(),
frame_num: FrameNum::new(0),
}
}
#[inline]
pub const fn flags(mut self, flags: Flags) -> Self {
self.flags = flags;
self
}
#[inline]
pub const fn frame_num(mut self, frame_num: FrameNum) -> Self {
self.frame_num = frame_num;
self
}
#[inline]
pub fn frame_num_from_seq(
self,
seq: &mut FrameNumSequence,
) -> Self {
self.frame_num(seq.advance())
}
#[inline]
pub const fn payload(self, payload: T) -> Frame<T> {
let Self { _marker, flags, frame_num } = self;
Frame { flags, frame_num, payload }
}
}
impl<T> Default for Builder<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
const fn calculate_frame_len(payload_len: usize) -> Option<usize> {
Header::SIZE.checked_add(payload_len)
}