use std::fmt;
use crate::error::*;
use crate::size;
use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut};
pub struct Option<B> {
buffer: B,
}
sized!(Option,
header {
min: 1,
max: 2,
size: p => match p.length() {
1 => 1,
_ => 2,
},
}
payload {
min: 0,
max: 32,
size: p => match p.length() {
1 => 0,
n => n as usize - 2,
},
});
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Number {
End,
NoOperation,
MaximumSegmentSize,
WindowScale,
SelectiveAcknowledgmentPermitted,
SelectiveAcknowledgment,
Timestamp,
Unknown(u8),
}
impl<B: AsRef<[u8]>> fmt::Debug for Option<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("tcp::Option")
.field("number", &self.number())
.field("length", &self.length())
.field("payload", &self.payload())
.finish()
}
}
impl<B: AsRef<[u8]>> Option<B> {
pub fn new(buffer: B) -> Result<Option<B>> {
let option = Option {
buffer: buffer,
};
if option.buffer.as_ref().len() < <Self as size::header::Min>::min() {
Err(Error::SmallBuffer)?
}
if option.buffer.as_ref().len() < option.length() as usize {
Err(Error::SmallBuffer)?
}
Ok(option)
}
}
impl<B: AsRef<[u8]>> AsRef<[u8]> for Option<B> {
fn as_ref(&self) -> &[u8] {
use crate::size::Size;
&self.buffer.as_ref()[.. self.size()]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> AsMut<[u8]> for Option<B> {
fn as_mut(&mut self) -> &mut [u8] {
use crate::size::Size;
let size = self.size();
&mut self.buffer.as_mut()[.. size]
}
}
impl<'a, B: AsRef<[u8]>> AsPacket<'a, Option<&'a [u8]>> for B {
fn as_packet(&self) -> Result<Option<&[u8]>> {
Option::new(self.as_ref())
}
}
impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Option<&'a mut [u8]>> for B {
fn as_packet_mut(&mut self) -> Result<Option<&mut [u8]>> {
Option::new(self.as_mut())
}
}
impl<B: AsRef<[u8]>> P for Option<B> {
fn split(&self) -> (&[u8], &[u8]) {
match self.length() {
1 =>
self.buffer.as_ref().split_at(1),
length =>
self.buffer.as_ref()[.. length as usize].split_at(2),
}
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> PM for Option<B> {
fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) {
match self.length() {
1 =>
self.buffer.as_mut().split_at_mut(1),
length =>
self.buffer.as_mut()[.. length as usize].split_at_mut(2),
}
}
}
impl<B: AsRef<[u8]>> Option<B> {
pub fn number(&self) -> Number {
self.buffer.as_ref()[0].into()
}
pub fn length(&self) -> u8 {
match self.number() {
Number::End |
Number::NoOperation =>
1,
_ =>
self.buffer.as_ref()[1]
}
}
}
impl From<u8> for Number {
fn from(value: u8) -> Self {
use self::Number::*;
match value {
0 => End,
1 => NoOperation,
2 => MaximumSegmentSize,
3 => WindowScale,
4 => SelectiveAcknowledgmentPermitted,
5 => SelectiveAcknowledgment,
8 => Timestamp,
n => Unknown(n),
}
}
}
impl Into<u8> for Number {
fn into(self) -> u8 {
use self::Number::*;
match self {
End => 0,
NoOperation => 1,
MaximumSegmentSize => 2,
WindowScale => 3,
SelectiveAcknowledgmentPermitted => 4,
SelectiveAcknowledgment => 5,
Timestamp => 8,
Unknown(n) => n,
}
}
}