use ntex_bytes::{Bytes, BytesMut};
use crate::frame::{Frame, FrameError, Head, Kind, StreamId, util};
#[derive(Clone, Eq, PartialEq)]
pub struct Data {
stream_id: StreamId,
payload: Bytes,
flags: DataFlags,
}
#[derive(Default, Copy, Clone, Eq, PartialEq)]
struct DataFlags(u8);
const END_STREAM: u8 = 0x1;
const PADDED: u8 = 0x8;
const ALL: u8 = END_STREAM | PADDED;
impl Data {
pub fn new(stream_id: StreamId, payload: Bytes) -> Self {
assert!(!stream_id.is_zero());
Data {
payload,
stream_id,
flags: DataFlags::default(),
}
}
pub fn stream_id(&self) -> StreamId {
self.stream_id
}
pub fn is_end_stream(&self) -> bool {
self.flags.is_end_stream()
}
pub fn set_end_stream(&mut self) {
self.flags.set_end_stream();
}
pub fn is_padded(&self) -> bool {
self.flags.is_padded()
}
pub fn set_padded(&mut self) {
self.flags.set_padded();
}
pub fn payload(&self) -> &Bytes {
&self.payload
}
pub fn payload_mut(&mut self) -> &mut Bytes {
&mut self.payload
}
pub fn into_payload(self) -> Bytes {
self.payload
}
pub(crate) fn head(&self) -> Head {
Head::new(Kind::Data, self.flags.into(), self.stream_id)
}
pub(crate) fn load(head: Head, mut payload: Bytes) -> Result<Self, FrameError> {
let flags = DataFlags::load(head.flag());
if head.stream_id().is_zero() {
return Err(FrameError::InvalidStreamId);
}
if flags.is_padded() {
util::strip_padding(&mut payload)?;
}
Ok(Data {
flags,
payload,
stream_id: head.stream_id(),
})
}
pub(crate) fn encode(&self, dst: &mut BytesMut) {
self.head().encode(self.payload.len(), dst);
dst.extend_from_slice(&self.payload);
}
}
impl From<Data> for Frame {
fn from(src: Data) -> Self {
Frame::Data(src)
}
}
impl std::fmt::Debug for Data {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut f = fmt.debug_struct("Data");
f.field("stream_id", &self.stream_id);
f.field("data_len", &self.payload.len());
if !self.flags.is_empty() {
f.field("flags", &self.flags);
}
f.finish()
}
}
impl DataFlags {
fn load(bits: u8) -> DataFlags {
DataFlags(bits & ALL)
}
fn is_empty(self) -> bool {
self.0 == 0
}
fn is_end_stream(self) -> bool {
self.0 & END_STREAM == END_STREAM
}
fn set_end_stream(&mut self) {
self.0 |= END_STREAM;
}
fn is_padded(self) -> bool {
self.0 & PADDED == PADDED
}
fn set_padded(&mut self) {
self.0 |= PADDED;
}
}
impl From<DataFlags> for u8 {
fn from(src: DataFlags) -> u8 {
src.0
}
}
impl std::fmt::Debug for DataFlags {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
util::debug_flags(fmt, self.0)
.flag_if(self.is_end_stream(), "END_STREAM")
.flag_if(self.is_padded(), "PADDED")
.finish()
}
}