1use crate::error::TightBeamError;
4use crate::{Message, Version};
5
6#[cfg(feature = "builder")]
7use crate::builder::FrameBuilder;
8#[cfg(feature = "compress")]
9use crate::{
10 compress::{Compressor, Inflator},
11 error::CompressionError,
12 CompressedData,
13};
14
15pub mod basis_points;
17pub mod jitter;
18pub mod math;
19pub mod statistics;
20pub mod task;
21pub mod urn;
22
23pub use basis_points::BasisPoints;
24
25#[cfg(feature = "hex")]
27pub use ::hex_literal::hex;
28
29#[macro_export]
35macro_rules! impl_from {
36 ($source:ty, $param:ident => $target:ty: $($field:tt)*) => {
38 impl From<&$source> for $target {
39 fn from($param: &$source) -> Self {
40 $($field)*
41 }
42 }
43
44 impl From<$source> for $target {
45 fn from($param: $source) -> Self {
46 (&$param).into()
47 }
48 }
49 };
50
51 ($from_type:ty => $target:ident::$variant:ident) => {
53 impl From<$from_type> for $target {
54 fn from(err: $from_type) -> Self {
55 $target::$variant(err)
56 }
57 }
58 };
59
60 (#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident) => {
62 #[cfg($feature)]
63 impl From<$from_type> for $target {
64 fn from(err: $from_type) -> Self {
65 $target::$variant(err)
66 }
67 }
68 };
69
70 (#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident via $wrapper:path) => {
72 #[cfg($feature)]
73 impl From<$from_type> for $target {
74 fn from(err: $from_type) -> Self {
75 $target::$variant($wrapper(err))
76 }
77 }
78 };
79
80 ($from_type:ty => $target:ident::$variant:ident via $wrapper:path) => {
82 impl From<$from_type> for $target {
83 fn from(err: $from_type) -> Self {
84 $target::$variant($wrapper(err))
85 }
86 }
87 };
88
89 ($from_type:ty => $target:ident::$variant:ident extract $enum_variant:pat => $inner:ident else $fallback:expr) => {
91 impl From<$from_type> for $target {
92 fn from(err: $from_type) -> Self {
93 match err {
94 $enum_variant => $target::$variant($inner),
95 _ => $target::$variant($fallback),
96 }
97 }
98 }
99 };
100
101 (#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident extract $enum_variant:pat => $inner:ident else $fallback:expr) => {
103 #[cfg($feature)]
104 impl From<$from_type> for $target {
105 fn from(err: $from_type) -> Self {
106 match err {
107 $enum_variant => $target::$variant($inner),
108 _ => $target::$variant($fallback),
109 }
110 }
111 }
112 };
113
114 ($from_type:ty => $target:ident::$variant:ident discard) => {
116 impl From<$from_type> for $target {
117 fn from(_: $from_type) -> Self {
118 $target::$variant
119 }
120 }
121 };
122
123 (#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident discard) => {
125 #[cfg($feature)]
126 impl From<$from_type> for $target {
127 fn from(_: $from_type) -> Self {
128 $target::$variant
129 }
130 }
131 };
132
133 (<$($gen:ident),+> $from_type:ty => $target:ident::$variant:ident discard) => {
135 impl<$($gen),+> From<$from_type> for $target {
136 fn from(_: $from_type) -> Self {
137 $target::$variant
138 }
139 }
140 };
141
142 (#[cfg($feature:meta)] <$($gen:ident),+> $from_type:ty => $target:ident::$variant:ident discard) => {
144 #[cfg($feature)]
145 impl<$($gen),+> From<$from_type> for $target {
146 fn from(_: $from_type) -> Self {
147 $target::$variant
148 }
149 }
150 };
151
152 ($from_type:ty => $target:ident::$variant:ident via |$err:ident| $transform:expr) => {
154 impl From<$from_type> for $target {
155 fn from($err: $from_type) -> Self {
156 $target::$variant($transform)
157 }
158 }
159 };
160
161 (#[cfg($feature:meta)] $from_type:ty => $target:ident::$variant:ident via |$err:ident| $transform:expr) => {
163 #[cfg($feature)]
164 impl From<$from_type> for $target {
165 fn from($err: $from_type) -> Self {
166 $target::$variant($transform)
167 }
168 }
169 };
170}
171
172#[macro_export]
178macro_rules! impl_try_from {
179 ($source:ty, $param:ident => $target:ty: $field:ident) => {
181 impl TryFrom<$source> for $target {
182 type Error = $crate::error::TightBeamError;
183
184 fn try_from(mut $param: $source) -> Result<Self, Self::Error> {
185 $param.$field.take().ok_or($crate::error::TightBeamError::InvalidMetadata)
186 }
187 }
188 };
189
190 ($source:ty, $param:ident => $target:ty: $field:ident, $error:expr) => {
191 impl TryFrom<$source> for $target {
192 type Error = $crate::error::TightBeamError;
193
194 fn try_from(mut $param: $source) -> core::result::Result<Self, Self::Error> {
195 $param.$field.take().ok_or($error)
196 }
197 }
198 };
199
200 ($source:ty, $param:ident => $target:ty: metadata.$field:ident) => {
202 impl TryFrom<$source> for $target {
203 type Error = $crate::error::TightBeamError;
204
205 fn try_from(mut $param: $source) -> Result<Self, Self::Error> {
206 $param
207 .metadata
208 .$field
209 .take()
210 .ok_or($crate::error::TightBeamError::InvalidMetadata)
211 }
212 }
213 };
214
215 ($source:ty, $param:ident => $target:ty: metadata.$field:ident, $error:expr) => {
216 impl TryFrom<$source> for $target {
217 type Error = $crate::error::TightBeamError;
218
219 fn try_from(mut $param: $source) -> core::result::Result<Self, Self::Error> {
220 $param.metadata.$field.take().ok_or($error)
221 }
222 }
223 };
224}
225
226#[inline]
228pub fn encode<T: der::Encode>(value: &T) -> Result<Vec<u8>, TightBeamError> {
229 Ok(der::Encode::to_der(value)?)
230}
231
232#[inline]
235pub fn decode<'a, T: der::Decode<'a>>(content: &'a impl AsRef<[u8]>) -> Result<T, TightBeamError> {
236 Ok(der::Decode::from_der(content.as_ref())?)
237}
238
239pub fn compose<T: Message>(version: Version) -> FrameBuilder<T> {
245 FrameBuilder::from(version)
246}
247
248#[cfg(feature = "compress")]
250#[inline]
251pub fn compress(
252 data: impl AsRef<[u8]>,
253 compressor: &impl Compressor,
254 content_info: Option<crate::cms::signed_data::EncapsulatedContentInfo>,
255) -> Result<(Vec<u8>, CompressedData), CompressionError> {
256 let data = data.as_ref();
257 compressor.compress(data, content_info)
258}
259
260#[cfg(feature = "compress")]
262#[inline]
263pub fn decompress(data: impl AsRef<[u8]>, inflator: &impl Inflator) -> Result<Vec<u8>, CompressionError> {
264 let data = data.as_ref();
265 inflator.decompress(data)
266}
267
268#[cfg(feature = "digest")]
270#[inline]
271pub fn digest<D: digest::Digest + crate::der::oid::AssociatedOid>(
272 data: impl AsRef<[u8]>,
273) -> Result<crate::asn1::DigestInfo, TightBeamError> {
274 let data = data.as_ref();
275
276 let mut hasher = D::new();
277 hasher.update(data);
278
279 let algorithm = crate::asn1::AlgorithmIdentifier { oid: D::OID, parameters: None };
280 let digest = hasher.finalize();
281 let digest_octet_string = crate::asn1::OctetString::new(&digest[..])?;
282 Ok(crate::asn1::DigestInfo { algorithm, digest: digest_octet_string })
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 use crate::der::asn1::OctetStringRef;
290 use crate::der::oid::ObjectIdentifier;
291
292 #[test]
293 fn data_driven_der_round_trip() -> Result<(), TightBeamError> {
294 let oid_cases = [
296 ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1"),
297 ObjectIdentifier::new_unwrap("1.3.6.1.5.5.7.3.1"),
298 ObjectIdentifier::new_unwrap("2.5.4.3"),
299 ];
300
301 let octet_cases: &[&[u8]] = &[
303 b"",
304 b"a",
305 b"hello",
306 b"The quick brown fox jumps over the lazy dog",
307 &(0u16..64).map(|v| (v % 251) as u8).collect::<Vec<u8>>(),
308 ];
309
310 for oid in oid_cases {
311 let enc = encode(&oid)?;
312 assert!(!enc.is_empty());
313 assert_eq!(enc[0], 0x06);
314
315 let dec: ObjectIdentifier = decode(&enc)?;
316 assert_eq!(dec, oid);
317 }
318
319 for data in octet_cases {
320 let oct = OctetStringRef::new(data)?;
321 let enc = encode(&oct)?;
322 assert_eq!(enc[0], 0x04);
323
324 let dec: OctetStringRef<'_> = decode(&enc)?;
325 assert_eq!(dec.as_bytes(), *data);
326 }
327
328 Ok(())
329 }
330
331 #[test]
332 #[cfg(feature = "compress")]
333 fn test_compress_decompress() -> Result<(), CompressionError> {
334 use crate::compress::ZstdCompression;
335
336 let patterned = (0u32..2048).map(|i| (i % 251) as u8).collect::<Vec<u8>>();
338 let big_repeat = vec![b'a'; 16 * 1024];
339 let cases: Vec<&[u8]> = vec![
340 b"",
341 b"a",
342 b"hello world",
343 b"The quick brown fox jumps over the lazy dog",
344 &patterned,
345 &big_repeat,
346 ];
347
348 let compressor = ZstdCompression;
349 for &data in &cases {
350 let (compressed, _info) = compress(data, &compressor, None)?;
351 let decompressed = decompress(&compressed, &compressor)?;
352 assert_eq!(decompressed, data);
353 }
354
355 Ok(())
356 }
357}