use crate::error::TightBeamError;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(feature = "builder")]
use crate::builder::FrameBuilder;
#[cfg(feature = "compress")]
use crate::{
compress::{Compressor, Inflator},
error::CompressionError,
CompressedData,
};
#[cfg(feature = "builder")]
use crate::{Message, Version};
pub mod basis_points;
pub mod jitter;
pub mod marker;
pub mod math;
pub mod statistics;
pub mod task;
pub mod urn;
pub use basis_points::{BasisPoints, BasisPointsOutOfRange};
#[cfg(feature = "hex")]
pub use ::hex_literal::hex;
#[macro_export]
macro_rules! impl_from {
($source:ty, $param:ident => $target:ty: $($field:tt)*) => {
impl From<&$source> for $target {
fn from($param: &$source) -> Self {
$($field)*
}
}
impl From<$source> for $target {
fn from($param: $source) -> Self {
(&$param).into()
}
}
};
($from_type:ty => $target:ident::$variant:ident) => {
impl From<$from_type> for $target {
fn from(err: $from_type) -> Self {
$target::$variant(err)
}
}
};
(#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident) => {
#[cfg($feature)]
impl From<$from_type> for $target {
fn from(err: $from_type) -> Self {
$target::$variant(err)
}
}
};
(#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident via $wrapper:path) => {
#[cfg($feature)]
impl From<$from_type> for $target {
fn from(err: $from_type) -> Self {
$target::$variant($wrapper(err))
}
}
};
($from_type:ty => $target:ident::$variant:ident via $wrapper:path) => {
impl From<$from_type> for $target {
fn from(err: $from_type) -> Self {
$target::$variant($wrapper(err))
}
}
};
($from_type:ty => $target:ident::$variant:ident extract $enum_variant:pat => $inner:ident else $fallback:expr) => {
impl From<$from_type> for $target {
fn from(err: $from_type) -> Self {
match err {
$enum_variant => $target::$variant($inner),
_ => $target::$variant($fallback),
}
}
}
};
(#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident extract $enum_variant:pat => $inner:ident else $fallback:expr) => {
#[cfg($feature)]
impl From<$from_type> for $target {
fn from(err: $from_type) -> Self {
match err {
$enum_variant => $target::$variant($inner),
_ => $target::$variant($fallback),
}
}
}
};
($from_type:ty => $target:ident::$variant:ident discard) => {
impl From<$from_type> for $target {
fn from(_: $from_type) -> Self {
$target::$variant
}
}
};
(#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident discard) => {
#[cfg($feature)]
impl From<$from_type> for $target {
fn from(_: $from_type) -> Self {
$target::$variant
}
}
};
(<$($gen:ident),+> $from_type:ty => $target:ident::$variant:ident discard) => {
impl<$($gen),+> From<$from_type> for $target {
fn from(_: $from_type) -> Self {
$target::$variant
}
}
};
(#[cfg($feature:meta)] <$($gen:ident),+> $from_type:ty => $target:ident::$variant:ident discard) => {
#[cfg($feature)]
impl<$($gen),+> From<$from_type> for $target {
fn from(_: $from_type) -> Self {
$target::$variant
}
}
};
($from_type:ty => $target:ident::$variant:ident via |$err:ident| $transform:expr) => {
impl From<$from_type> for $target {
fn from($err: $from_type) -> Self {
$target::$variant($transform)
}
}
};
(#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident via |$err:ident| $transform:expr) => {
#[cfg($feature)]
impl From<$from_type> for $target {
fn from($err: $from_type) -> Self {
$target::$variant($transform)
}
}
};
}
#[macro_export]
macro_rules! impl_try_from {
($source:ty, $param:ident => $target:ty: $field:ident) => {
impl TryFrom<$source> for $target {
type Error = $crate::error::TightBeamError;
fn try_from(mut $param: $source) -> Result<Self, Self::Error> {
$param.$field.take().ok_or($crate::error::TightBeamError::InvalidMetadata)
}
}
};
($source:ty, $param:ident => $target:ty: $field:ident, $error:expr) => {
impl TryFrom<$source> for $target {
type Error = $crate::error::TightBeamError;
fn try_from(mut $param: $source) -> core::result::Result<Self, Self::Error> {
$param.$field.take().ok_or($error)
}
}
};
($source:ty, $param:ident => $target:ty: metadata.$field:ident) => {
impl TryFrom<$source> for $target {
type Error = $crate::error::TightBeamError;
fn try_from(mut $param: $source) -> Result<Self, Self::Error> {
$param
.metadata
.$field
.take()
.ok_or($crate::error::TightBeamError::InvalidMetadata)
}
}
};
($source:ty, $param:ident => $target:ty: metadata.$field:ident, $error:expr) => {
impl TryFrom<$source> for $target {
type Error = $crate::error::TightBeamError;
fn try_from(mut $param: $source) -> core::result::Result<Self, Self::Error> {
$param.metadata.$field.take().ok_or($error)
}
}
};
}
#[inline]
pub fn encode<T: der::Encode>(value: &T) -> Result<Vec<u8>, TightBeamError> {
Ok(der::Encode::to_der(value)?)
}
#[inline]
pub fn decode<'a, T: der::Decode<'a>>(content: &'a impl AsRef<[u8]>) -> Result<T, TightBeamError> {
Ok(der::Decode::from_der(content.as_ref())?)
}
#[cfg(feature = "builder")]
pub fn compose<T: Message>(version: Version) -> FrameBuilder<T> {
FrameBuilder::from(version)
}
#[cfg(feature = "compress")]
#[inline]
pub fn compress(
data: impl AsRef<[u8]>,
compressor: &impl Compressor,
content_info: Option<crate::cms::signed_data::EncapsulatedContentInfo>,
) -> Result<(Vec<u8>, CompressedData), CompressionError> {
let data = data.as_ref();
compressor.compress(data, content_info)
}
#[cfg(feature = "compress")]
#[inline]
pub fn decompress(data: impl AsRef<[u8]>, inflator: &impl Inflator) -> Result<Vec<u8>, TightBeamError> {
let data = data.as_ref();
inflator.decompress(data)
}
#[cfg(feature = "digest")]
#[inline]
pub fn digest<D: digest::Digest + crate::der::oid::AssociatedOid>(
data: impl AsRef<[u8]>,
) -> Result<crate::asn1::DigestInfo, TightBeamError> {
let data = data.as_ref();
let mut hasher = D::new();
hasher.update(data);
let algorithm = crate::asn1::AlgorithmIdentifier { oid: D::OID, parameters: None };
let digest = hasher.finalize();
let digest_octet_string = crate::asn1::OctetString::new(&digest[..])?;
Ok(crate::asn1::DigestInfo { algorithm, digest: digest_octet_string })
}
#[cfg(test)]
mod tests {
use super::*;
use crate::der::asn1::OctetStringRef;
use crate::der::oid::ObjectIdentifier;
#[test]
fn data_driven_der_round_trip() -> Result<(), TightBeamError> {
let oid_cases = [
ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1"),
ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.1"),
ObjectIdentifier::new_unwrap("2.5.4.3"),
];
let octet_cases: &[&[u8]] = &[
b"",
b"a",
b"hello",
b"The quick brown fox jumps over the lazy dog",
&(0u16..64).map(|v| (v % 251) as u8).collect::<Vec<u8>>(),
];
for oid in oid_cases {
let enc = encode(&oid)?;
assert!(!enc.is_empty());
assert_eq!(enc[0], 0x06);
let dec: ObjectIdentifier = decode(&enc)?;
assert_eq!(dec, oid);
}
for data in octet_cases {
let oct = OctetStringRef::new(data)?;
let enc = encode(&oct)?;
assert_eq!(enc[0], 0x04);
let dec: OctetStringRef<'_> = decode(&enc)?;
assert_eq!(dec.as_bytes(), *data);
}
Ok(())
}
#[test]
#[cfg(feature = "compress")]
fn test_compress_decompress() -> Result<(), TightBeamError> {
use crate::compress::ZstdCompression;
let patterned = (0u32..2048).map(|i| (i % 251) as u8).collect::<Vec<u8>>();
let big_repeat = vec![b'a'; 16 * 1024];
let cases: Vec<&[u8]> = vec![
b"",
b"a",
b"hello world",
b"The quick brown fox jumps over the lazy dog",
&patterned,
&big_repeat,
];
let compressor = ZstdCompression::default();
for &data in &cases {
let (compressed, _info) = compress(data, &compressor, None)?;
let decompressed = decompress(&compressed, &compressor)?;
assert_eq!(decompressed, data);
}
Ok(())
}
}