use crate::{CloseFrame, Frame, OpCode, error::FragmentationError, fragments::FragmentsIterator};
#[derive(Debug)]
pub enum Message<'a> {
Text(&'a str),
Binary(&'a [u8]),
Ping(&'a [u8]),
Pong(&'a [u8]),
Close(Option<CloseFrame<'a>>),
}
impl<'a> Message<'a> {
pub const fn is_text(&self) -> bool {
matches!(*self, Message::Text(_))
}
pub const fn is_binary(&self) -> bool {
matches!(*self, Message::Binary(_))
}
pub const fn is_ping(&self) -> bool {
matches!(*self, Message::Ping(_))
}
pub const fn is_pong(&self) -> bool {
matches!(*self, Message::Pong(_))
}
pub const fn is_close(&self) -> bool {
matches!(*self, Message::Close(_))
}
pub(crate) const fn opcode(&self) -> OpCode {
match self {
Message::Text(_) => OpCode::Text,
Message::Binary(_) => OpCode::Binary,
Message::Ping(_) => OpCode::Ping,
Message::Pong(_) => OpCode::Pong,
Message::Close(_) => OpCode::Close,
}
}
pub(crate) const fn payload_len(&self) -> usize {
match self {
Message::Text(payload) => payload.len(),
Message::Binary(payload) => payload.len(),
Message::Ping(payload) => payload.len(),
Message::Pong(payload) => payload.len(),
Message::Close(Some(frame)) => 2 + frame.reason().len(),
Message::Close(None) => 0,
}
}
pub(crate) fn write(&self, dst: &mut [u8]) -> Option<usize> {
if dst.len() < self.payload_len() {
return None;
}
match self {
Message::Text(payload) => {
dst[..payload.len()].copy_from_slice(payload.as_bytes());
}
Message::Binary(payload) => {
dst[..payload.len()].copy_from_slice(payload);
}
Message::Ping(payload) => {
dst[..payload.len()].copy_from_slice(payload);
}
Message::Pong(payload) => {
dst[..payload.len()].copy_from_slice(payload);
}
Message::Close(Some(frame)) => {
let code: u16 = frame.code().into_u16();
let code = code.to_be_bytes();
dst[0..2].copy_from_slice(&code);
dst[2..2 + frame.reason().len()].copy_from_slice(frame.reason().as_bytes());
}
Message::Close(None) => {}
}
Some(self.payload_len())
}
pub(crate) fn fragments(
&self,
fragment_size: usize,
) -> Result<impl Iterator<Item = Frame<'a>>, FragmentationError> {
if fragment_size < 1 {
return Err(FragmentationError::InvalidFragmentSize);
}
match self {
Message::Text(payload) => Ok(FragmentsIterator::new(
OpCode::Text,
payload.as_bytes(),
fragment_size,
)),
Message::Binary(payload) => Ok(FragmentsIterator::new(
OpCode::Binary,
payload,
fragment_size,
)),
_ => Err(FragmentationError::CanNotBeFragmented),
}
}
}