use core::fmt;
use bytes::{Buf, BufMut, Bytes};
use nex_core::bitfield::u16be;
use crate::packet::{GenericMutablePacket, Packet};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u16)]
pub enum FlowControlOpcode {
Pause = 0x0001,
Unknown(u16),
}
impl FlowControlOpcode {
pub fn new(value: u16) -> Self {
match value {
0x0001 => FlowControlOpcode::Pause,
other => FlowControlOpcode::Unknown(other),
}
}
pub fn value(&self) -> u16 {
match *self {
FlowControlOpcode::Pause => 0x0001,
FlowControlOpcode::Unknown(v) => v,
}
}
}
impl fmt::Display for FlowControlOpcode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
FlowControlOpcode::Pause => "pause",
FlowControlOpcode::Unknown(_) => "unknown",
}
)
}
}
pub struct FlowControlPacket {
pub command: FlowControlOpcode,
pub quanta: u16be,
pub payload: Bytes,
}
impl Packet for FlowControlPacket {
type Header = ();
fn from_buf(mut bytes: &[u8]) -> Option<Self> {
if bytes.len() < 4 {
return None;
}
let command = FlowControlOpcode::new(bytes.get_u16());
let quanta = bytes.get_u16();
let payload = Bytes::copy_from_slice(bytes);
Some(Self {
command,
quanta: quanta.into(),
payload,
})
}
fn from_bytes(bytes: Bytes) -> Option<Self> {
Self::from_buf(&bytes)
}
fn to_bytes(&self) -> Bytes {
let mut buf = bytes::BytesMut::with_capacity(4 + self.payload.len());
buf.put_u16(self.command.value());
buf.put_u16(self.quanta.into());
buf.put_slice(&self.payload);
buf.freeze()
}
fn header(&self) -> Bytes {
let mut buf = bytes::BytesMut::with_capacity(4);
buf.put_u16(self.command.value());
buf.put_u16(self.quanta.into());
buf.freeze()
}
fn payload(&self) -> Bytes {
self.payload.clone()
}
fn header_len(&self) -> usize {
4
}
fn payload_len(&self) -> usize {
self.payload.len()
}
fn total_len(&self) -> usize {
self.header_len() + self.payload_len()
}
fn into_parts(self) -> (Self::Header, Bytes) {
((), self.to_bytes())
}
}
pub type MutableFlowControlPacket<'a> = GenericMutablePacket<'a, FlowControlPacket>;
#[cfg(test)]
mod tests {
use super::*;
use crate::packet::MutablePacket;
#[test]
fn flowcontrol_pause_test() {
let packet = Bytes::from_static(&[
0x00, 0x01, 0x12, 0x34, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, ]);
let fc_packet = FlowControlPacket::from_bytes(packet.clone()).unwrap();
assert_eq!(fc_packet.command, FlowControlOpcode::Pause);
assert_eq!(fc_packet.quanta, 0x1234);
assert_eq!(fc_packet.to_bytes(), packet);
}
#[test]
fn flowcontrol_mutable_packet() {
let mut raw = [
0x00, 0x01, 0x12, 0x34, 0xaa, 0xbb,
];
let mut packet = <MutableFlowControlPacket as MutablePacket>::new(&mut raw)
.expect("mutable flowcontrol");
packet.header_mut()[0] = 0x00;
packet.header_mut()[1] = 0x02;
packet.payload_mut()[0] = 0xff;
let frozen = packet.freeze().expect("freeze");
assert_eq!(frozen.command, FlowControlOpcode::Unknown(2));
assert_eq!(frozen.payload[0], 0xff);
}
}