use super::super::iana::OptionCode;
use super::super::message_builder::OptBuilder;
use super::super::wire::{Compose, Composer, Parse, ParseError};
use super::{ComposeOptData, Opt, OptData, ParseOptData};
use core::fmt;
use octseq::builder::OctetsBuilder;
use octseq::octets::Octets;
use octseq::parse::Parser;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct Expire(Option<u32>);
impl Expire {
pub(super) const CODE: OptionCode = OptionCode::EXPIRE;
#[must_use]
pub fn new(expire: Option<u32>) -> Self {
Expire(expire)
}
#[must_use]
pub fn expire(self) -> Option<u32> {
self.0
}
pub fn parse<Octs: AsRef<[u8]>>(
parser: &mut Parser<'_, Octs>,
) -> Result<Self, ParseError> {
if parser.remaining() == 0 {
Ok(Expire::new(None))
} else {
u32::parse(parser).map(|res| Expire::new(Some(res)))
}
}
pub(super) fn try_octets_from<E>(src: Self) -> Result<Self, E> {
Ok(src)
}
}
impl OptData for Expire {
fn code(&self) -> OptionCode {
OptionCode::EXPIRE
}
}
impl<'a, Octs: AsRef<[u8]>> ParseOptData<'a, Octs> for Expire {
fn parse_option(
code: OptionCode,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if code == OptionCode::EXPIRE {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
impl ComposeOptData for Expire {
fn compose_len(&self) -> u16 {
match self.0 {
Some(_) => u32::COMPOSE_LEN,
None => 0,
}
}
fn compose_option<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
if let Some(value) = self.0 {
value.compose(target)?;
}
Ok(())
}
}
impl fmt::Display for Expire {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(expire) => expire.fmt(f),
None => Ok(()),
}
}
}
impl<Octs: Octets> Opt<Octs> {
pub fn expire(&self) -> Option<Expire> {
self.first()
}
}
impl<Target: Composer> OptBuilder<'_, Target> {
pub fn expire(
&mut self,
expire: Option<u32>,
) -> Result<(), Target::AppendError> {
self.push(&Expire::new(expire))
}
}
#[cfg(test)]
#[cfg(all(feature = "std", feature = "bytes"))]
mod test {
use super::super::test::test_option_compose_parse;
use super::*;
#[test]
#[allow(clippy::redundant_closure)] fn expire_compose_parse() {
test_option_compose_parse(&Expire::new(None), |parser| {
Expire::parse(parser)
});
test_option_compose_parse(&Expire::new(Some(12)), |parser| {
Expire::parse(parser)
});
}
}