use core::{borrow, fmt, str};
use super::super::iana::OptionCode;
use super::super::message_builder::OptBuilder;
use super::super::wire::{Compose, Composer, ParseError};
use super::{LongOptData, OptData, ComposeOptData, ParseOptData};
use octseq::builder::OctetsBuilder;
use octseq::octets::{Octets, OctetsFrom};
use octseq::parse::Parser;
#[derive(Clone, Copy)]
pub struct Padding<Octs: ?Sized> {
octets: Octs,
}
impl Padding<()> {
pub const CODE: OptionCode = OptionCode::PADDING;
}
impl<Octs> Padding<Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, LongOptData>
where Octs: AsRef<[u8]> {
LongOptData::check_len(octets.as_ref().len())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
Self { octets }
}
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>
) -> Result<Self, ParseError> {
let len = parser.remaining();
LongOptData::check_len(len)?;
Ok(unsafe { Self::from_octets_unchecked(
parser.parse_octets(len)?
)})
}
}
impl<Octs: ?Sized> Padding<Octs> {
pub fn as_octets(&self) -> &Octs {
&self.octets
}
pub fn into_octets(self) -> Octs
where
Octs: Sized,
{
self.octets
}
pub fn as_slice(&self) -> &[u8]
where
Octs: AsRef<[u8]>,
{
self.octets.as_ref()
}
}
impl<Octs, SrcOcts> OctetsFrom<Padding<SrcOcts>> for Padding<Octs>
where Octs: OctetsFrom<SrcOcts> {
type Error = Octs::Error;
fn try_octets_from(src: Padding<SrcOcts>) -> Result<Self, Self::Error> {
Octs::try_octets_from(src.octets).map(|octets| unsafe {
Self::from_octets_unchecked(octets)
})
}
}
impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Padding<Octs> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<Octs: AsRef<[u8]> + ?Sized> borrow::Borrow<[u8]> for Padding<Octs> {
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl<Octs> OptData for Padding<Octs> {
fn code(&self) -> OptionCode {
OptionCode::PADDING
}
}
impl<'a, Octs: Octets> ParseOptData<'a, Octs> for Padding<Octs::Range<'a>> {
fn parse_option(
code: OptionCode,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if code == OptionCode::PADDING {
Self::parse(parser).map(Some)
}
else {
Ok(None)
}
}
}
impl<Octs: AsRef<[u8]>> ComposeOptData for Padding<Octs> {
fn compose_len(&self) -> u16 {
self.octets.as_ref().len().try_into().expect("long option data")
}
fn compose_option<Target: OctetsBuilder + ?Sized>(
&self, target: &mut Target
) -> Result<(), Target::AppendError> {
target.append_slice(self.octets.as_ref())
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Padding<Octs> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for v in self.octets.as_ref() {
write!(f, "{:X} ", *v)?;
}
if let Ok(s) = str::from_utf8(self.octets.as_ref()) {
write!(f, "({})", s)?;
}
Ok(())
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Padding<Octs> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Padding({})", self)
}
}
impl<'a, Target: Composer> OptBuilder<'a, Target> {
pub fn padding( &mut self, len: u16) -> Result<(), Target::AppendError> {
self.push_raw_option(
OptionCode::PADDING,
len,
|target| {
for _ in 0..len {
0u8.compose(target)?
}
Ok(())
}
)
}
#[cfg(feature = "rand")]
pub fn random_padding(
&mut self, len: u16
) -> Result<(), Target::AppendError> {
self.push_raw_option(
OptionCode::PADDING,
len,
|target| {
for _ in 0..len {
rand::random::<u8>().compose(target)?
}
Ok(())
}
)
}
}
#[cfg(feature = "serde")]
impl<Octs: AsRef<[u8]>> serde::Serialize for Padding<Octs> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer {
use octseq::serde::SerializeOctets;
self.octets.as_ref().serialize_octets(serializer)
}
}