use crate::{
collection::{ArrayVectorU8, Vector},
misc::Lease,
web_socket::{
MASK_MASK, MAX_CONTROL_PAYLOAD_LEN, MAX_HEADER_LEN, OpCode,
misc::{fill_header_from_params, has_masked_frame},
},
};
use core::str;
pub type FrameControlArray<const IS_CLIENT: bool> =
Frame<ArrayVectorU8<u8, MAX_CONTROL_PAYLOAD_LEN>, IS_CLIENT>;
pub type FrameMut<'bytes, const IS_CLIENT: bool> = Frame<&'bytes mut [u8], IS_CLIENT>;
pub type FrameRef<'bytes, const IS_CLIENT: bool> = Frame<&'bytes [u8], IS_CLIENT>;
pub type FrameVector<const IS_CLIENT: bool> = Frame<Vector<u8>, IS_CLIENT>;
pub type FrameVectorMut<'bytes, const IS_CLIENT: bool> = Frame<&'bytes mut Vector<u8>, IS_CLIENT>;
pub type FrameVectorRef<'bytes, const IS_CLIENT: bool> = Frame<&'bytes Vector<u8>, IS_CLIENT>;
#[derive(Debug)]
pub struct Frame<P, const IS_CLIENT: bool> {
fin: bool,
header: [u8; MAX_HEADER_LEN],
header_len: u8,
op_code: OpCode,
payload: P,
}
impl<P, const IS_CLIENT: bool> Frame<P, IS_CLIENT> {
#[inline]
pub const fn fin(&self) -> bool {
self.fin
}
#[inline]
pub fn header_and_payload(&self) -> (&[u8], &P) {
(self.header(), &self.payload)
}
#[inline]
pub const fn op_code(&self) -> OpCode {
self.op_code
}
#[inline]
pub const fn payload(&self) -> &P {
&self.payload
}
#[inline]
pub const fn payload_mut(&mut self) -> &mut P {
&mut self.payload
}
pub(crate) fn header(&self) -> &[u8] {
self.header.get(..self.header_len.into()).unwrap_or_default()
}
pub(crate) fn header_and_payload_mut(&mut self) -> (&mut [u8], &mut P) {
(self.header.get_mut(..self.header_len.into()).unwrap_or_default(), &mut self.payload)
}
pub(crate) const fn header_first_two_mut(&mut self) -> [&mut u8; 2] {
let [a, b, ..] = &mut self.header;
[a, b]
}
pub(crate) fn set_mask(&mut self, mask: [u8; 4]) {
if has_masked_frame(self.header[1]) {
return;
}
self.header_len = self.header_len.wrapping_add(4);
if let Some([_, a, .., b, c, d, e]) = self.header.get_mut(..self.header_len.into()) {
*a |= MASK_MASK;
*b = mask[0];
*c = mask[1];
*d = mask[2];
*e = mask[3];
}
}
}
impl<P, const IS_CLIENT: bool> Frame<P, IS_CLIENT>
where
P: Lease<[u8]>,
{
#[inline]
pub fn new_fin(op_code: OpCode, payload: P) -> Self {
Self::new(true, op_code, payload, 0)
}
#[inline]
pub fn new_unfin(op_code: OpCode, payload: P) -> Self {
Self::new(false, op_code, payload, 0)
}
#[inline]
pub fn text_payload(&self) -> Option<&str> {
matches!(self.op_code, OpCode::Text | OpCode::Close).then(|| {
unsafe { str::from_utf8_unchecked(self.payload.lease()) }
})
}
#[inline]
pub fn to_vector(&self) -> crate::Result<FrameVector<IS_CLIENT>> {
Ok(FrameVector {
fin: self.fin,
header: self.header,
header_len: self.header_len,
op_code: self.op_code,
payload: Vector::from_copyable_slice(self.payload.lease())?,
})
}
pub(crate) fn new(fin: bool, op_code: OpCode, payload: P, rsv1: u8) -> Self {
let mut header = [0; MAX_HEADER_LEN];
let payload_len = if op_code.is_control() {
payload.lease().len().min(MAX_CONTROL_PAYLOAD_LEN)
} else {
payload.lease().len()
};
let len = fill_header_from_params::<IS_CLIENT>(fin, &mut header, op_code, payload_len, rsv1);
Self { fin, header, header_len: len, op_code, payload }
}
}