use super::super::iana::{OptionCode, SecurityAlgorithm};
use super::super::message_builder::OptBuilder;
use super::super::wire::{Compose, Composer, ParseError};
use super::{
BuildDataError, ComposeOptData, LongOptData, Opt, OptData, ParseOptData,
};
use core::marker::PhantomData;
use core::{borrow, fmt, hash, mem, slice};
use octseq::builder::{EmptyBuilder, FromBuilder, OctetsBuilder};
use octseq::octets::{Octets, OctetsFrom};
use octseq::parse::Parser;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Understood<Variant, Octs: ?Sized> {
marker: PhantomData<Variant>,
octets: Octs,
}
#[derive(Clone, Copy, Debug)]
pub struct DauVariant;
#[derive(Clone, Copy, Debug)]
pub struct DhuVariant;
#[derive(Clone, Copy, Debug)]
pub struct N3uVariant;
pub type Dau<Octs> = Understood<DauVariant, Octs>;
pub type Dhu<Octs> = Understood<DhuVariant, Octs>;
pub type N3u<Octs> = Understood<N3uVariant, Octs>;
impl<Variant, Octs> Understood<Variant, Octs> {
pub fn from_octets(octets: Octs) -> Result<Self, ParseError>
where
Octs: AsRef<[u8]>,
{
Understood::<Variant, _>::check_slice(octets.as_ref())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
Understood {
marker: PhantomData,
octets,
}
}
pub fn from_sec_algs(
sec_algs: impl IntoIterator<Item = SecurityAlgorithm>,
) -> Result<Self, BuildDataError>
where
Octs: FromBuilder,
<Octs as FromBuilder>::Builder: EmptyBuilder,
{
let mut octets = EmptyBuilder::empty();
for item in sec_algs {
item.compose(&mut octets)?;
}
let octets = Octs::from_builder(octets);
LongOptData::check_len(octets.as_ref().len())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
impl<Variant> Understood<Variant, [u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
Understood::<Variant, _>::check_slice(slice)?;
Ok(unsafe { Self::from_slice_unchecked(slice) })
}
#[must_use]
pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
mem::transmute(slice)
}
fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
LongOptData::check_len(slice.len())?;
if !slice.len().is_multiple_of(usize::from(u16::COMPOSE_LEN)) {
return Err(ParseError::form_error("invalid understood data"));
}
Ok(())
}
}
impl<Variant, Octs: AsRef<[u8]>> Understood<Variant, Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
Self::from_octets(parser.parse_octets(parser.remaining())?)
}
}
impl<Variant, Octs: ?Sized> Understood<Variant, 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()
}
pub fn for_slice(&self) -> &Understood<Variant, [u8]>
where
Octs: AsRef<[u8]>,
{
unsafe {
Understood::<Variant, _>::from_slice_unchecked(
self.octets.as_ref(),
)
}
}
pub fn iter(&self) -> SecurityAlgorithmIter<'_>
where
Octs: AsRef<[u8]>,
{
SecurityAlgorithmIter::new(self.octets.as_ref())
}
}
impl Understood<DauVariant, ()> {
pub(super) const CODE: OptionCode = OptionCode::DAU;
}
impl Understood<DhuVariant, ()> {
pub(super) const CODE: OptionCode = OptionCode::DHU;
}
impl Understood<N3uVariant, ()> {
pub(super) const CODE: OptionCode = OptionCode::N3U;
}
impl<Variant, O, OO> OctetsFrom<Understood<Variant, O>>
for Understood<Variant, OO>
where
OO: OctetsFrom<O>,
{
type Error = OO::Error;
fn try_octets_from(
source: Understood<Variant, O>,
) -> Result<Self, Self::Error> {
Ok(unsafe {
Self::from_octets_unchecked(OO::try_octets_from(source.octets)?)
})
}
}
impl<Variant, Octs> AsRef<[u8]> for Understood<Variant, Octs>
where
Octs: AsRef<[u8]> + ?Sized,
{
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<Variant, Octs> borrow::Borrow<[u8]> for Understood<Variant, Octs>
where
Octs: AsRef<[u8]> + ?Sized,
{
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl<Var, OtherVar, Octs, OtherOcts>
PartialEq<Understood<OtherVar, OtherOcts>> for Understood<Var, Octs>
where
Octs: AsRef<[u8]> + ?Sized,
OtherOcts: AsRef<[u8]> + ?Sized,
{
fn eq(&self, other: &Understood<OtherVar, OtherOcts>) -> bool {
self.as_slice().eq(other.as_slice())
}
}
impl<Variant, Octs: AsRef<[u8]> + ?Sized> Eq for Understood<Variant, Octs> {}
impl<Variant, Octs: AsRef<[u8]>> hash::Hash for Understood<Variant, Octs> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_slice().hash(state)
}
}
impl<Octs: ?Sized> OptData for Understood<DauVariant, Octs> {
fn code(&self) -> OptionCode {
OptionCode::DAU
}
}
impl<Octs: ?Sized> OptData for Understood<DhuVariant, Octs> {
fn code(&self) -> OptionCode {
OptionCode::DHU
}
}
impl<Octs: ?Sized> OptData for Understood<N3uVariant, Octs> {
fn code(&self) -> OptionCode {
OptionCode::N3U
}
}
impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
for Understood<DauVariant, Octs::Range<'a>>
{
fn parse_option(
code: OptionCode,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if code == OptionCode::DAU {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
for Understood<DhuVariant, Octs::Range<'a>>
{
fn parse_option(
code: OptionCode,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if code == OptionCode::DHU {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
for Understood<N3uVariant, Octs::Range<'a>>
{
fn parse_option(
code: OptionCode,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if code == OptionCode::N3U {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
impl<Variant, Octs> ComposeOptData for Understood<Variant, Octs>
where
Self: OptData,
Octs: AsRef<[u8]> + ?Sized,
{
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<'a, Variant, Octs> IntoIterator for &'a Understood<Variant, Octs>
where
Octs: AsRef<[u8]> + ?Sized,
{
type Item = SecurityAlgorithm;
type IntoIter = SecurityAlgorithmIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<Variant, Octs> fmt::Display for Understood<Variant, Octs>
where
Octs: AsRef<[u8]> + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
for v in self.octets.as_ref() {
if first {
write!(f, "{}", *v)?;
first = false;
} else {
write!(f, ", {}", *v)?
}
}
Ok(())
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<DauVariant, Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Understood<DauVariant>")
.field(&format_args!("{}", self))
.finish()
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<DhuVariant, Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Understood<DhuVariant>")
.field(&format_args!("{}", self))
.finish()
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<N3uVariant, Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Understood<N3uVariant>")
.field(&format_args!("{}", self))
.finish()
}
}
#[cfg(feature = "serde")]
impl<V, Octs: AsRef<[u8]>> serde::Serialize for Understood<V, Octs> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeSeq;
let mut list = serializer.serialize_seq(None)?;
for item in self.iter() {
list.serialize_element(&item)?;
}
list.end()
}
}
impl<Octs: Octets> Opt<Octs> {
pub fn dau(&self) -> Option<Dau<Octs::Range<'_>>> {
self.first()
}
pub fn dhu(&self) -> Option<Dhu<Octs::Range<'_>>> {
self.first()
}
pub fn n3u(&self) -> Option<N3u<Octs::Range<'_>>> {
self.first()
}
}
impl<Target: Composer> OptBuilder<'_, Target> {
pub fn dau(
&mut self,
algs: &impl AsRef<[SecurityAlgorithm]>,
) -> Result<(), BuildDataError> {
Ok(self.push_raw_option(
OptionCode::DAU,
u16::try_from(
algs.as_ref().len()
* usize::from(SecurityAlgorithm::COMPOSE_LEN),
)
.map_err(|_| BuildDataError::LongOptData)?,
|octs| {
algs.as_ref().iter().try_for_each(|item| item.compose(octs))
},
)?)
}
pub fn dhu(
&mut self,
algs: &impl AsRef<[SecurityAlgorithm]>,
) -> Result<(), BuildDataError> {
Ok(self.push_raw_option(
OptionCode::DHU,
u16::try_from(
algs.as_ref().len()
* usize::from(SecurityAlgorithm::COMPOSE_LEN),
)
.map_err(|_| BuildDataError::LongOptData)?,
|octs| {
algs.as_ref().iter().try_for_each(|item| item.compose(octs))
},
)?)
}
pub fn n3u(
&mut self,
algs: &impl AsRef<[SecurityAlgorithm]>,
) -> Result<(), BuildDataError> {
Ok(self.push_raw_option(
OptionCode::N3U,
u16::try_from(
algs.as_ref().len()
* usize::from(SecurityAlgorithm::COMPOSE_LEN),
)
.map_err(|_| BuildDataError::LongOptData)?,
|octs| {
algs.as_ref().iter().try_for_each(|item| item.compose(octs))
},
)?)
}
}
pub struct SecurityAlgorithmIter<'a>(slice::Iter<'a, u8>);
impl<'a> SecurityAlgorithmIter<'a> {
fn new(slice: &'a [u8]) -> Self {
SecurityAlgorithmIter(slice.iter())
}
}
impl Iterator for SecurityAlgorithmIter<'_> {
type Item = SecurityAlgorithm;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|x| SecurityAlgorithm::from_int(*x))
}
}
#[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 dau_compose_parse() {
test_option_compose_parse(
&Dau::from_octets("foof").unwrap(),
|parser| Dau::parse(parser),
);
}
}