Skip to content

Commit caf3a6c

Browse files
authored
Add decoding iterator, decode_with_remainder, clippy fixes (#421)
1 parent 68dfdb5 commit caf3a6c

16 files changed

+274
-41
lines changed
Binary file not shown.

macros/macros_impl/src/encode.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@ pub fn derive_struct_impl(
8080
)
8181
}
8282
} else {
83-
let operation = config
84-
.set
85-
.then(|| quote!(encode_set))
86-
.unwrap_or_else(|| quote!(encode_sequence));
83+
let operation = if config.set {
84+
quote!(encode_set)
85+
} else {
86+
quote!(encode_sequence)
87+
};
8788

8889
let encode_impl = quote! {
8990
// In order to avoid unnecessary allocations, we provide the constant field counts to the encoder when encoding sequences and sets.

macros/macros_impl/src/enum.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,11 @@ impl Enum<'_> {
6666

6767
let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
6868

69-
let return_val = self
70-
.config
71-
.tag
72-
.is_some()
73-
.then(|| quote!(#crate_root::types::TagTree::Leaf(Self::TAG)))
74-
.unwrap_or_else(|| quote!(tag_tree));
69+
let return_val = if self.config.tag.is_some() {
70+
quote!(#crate_root::types::TagTree::Leaf(Self::TAG))
71+
} else {
72+
quote!(tag_tree)
73+
};
7574

7675
let identifiers = variant_configs
7776
.iter()

src/aper.rs

+9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ pub use super::per::*;
1111
pub fn decode<T: crate::Decode>(input: &[u8]) -> Result<T, crate::error::DecodeError> {
1212
crate::per::decode(de::DecoderOptions::aligned(), input)
1313
}
14+
/// Attempts to decode `T` from `input` using APER-BASIC. Returns both `T` and reference to the remainder of the input.
15+
///
16+
/// # Errors
17+
/// Returns `DecodeError` if `input` is not valid APER-BASIC encoding specific to the expected type.
18+
pub fn decode_with_remainder<T: crate::Decode>(
19+
input: &[u8],
20+
) -> Result<(T, &[u8]), crate::error::DecodeError> {
21+
crate::per::decode_with_remainder(de::DecoderOptions::aligned(), input)
22+
}
1423

1524
/// Attempts to encode `value` to APER-CANONICAL.
1625
pub fn encode<T: crate::Encode>(

src/ber.rs

+12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ pub fn decode<T: crate::Decode>(input: &[u8]) -> Result<T, crate::error::DecodeE
1515
T::decode(&mut de::Decoder::new(input, de::DecoderOptions::ber()))
1616
}
1717

18+
/// Attempts to decode `T` from `input` using BER. Returns both `T` and reference to the remainder of the input.
19+
///
20+
/// # Errors
21+
/// Returns `DecodeError` if `input` is not valid BER encoding specific to the expected type.
22+
pub fn decode_with_remainder<T: crate::Decode>(
23+
input: &[u8],
24+
) -> Result<(T, &[u8]), crate::error::DecodeError> {
25+
let decoder = &mut de::Decoder::new(input, de::DecoderOptions::ber());
26+
let decoded = T::decode(decoder)?;
27+
Ok((decoded, decoder.remaining()))
28+
}
29+
1830
/// Attempts to encode `value` to BER.
1931
/// # Errors
2032
/// Returns error specific to BER encoder if encoding is not possible.

src/ber/de.rs

+5
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ impl<'input> Decoder<'input> {
3737
pub fn codec(&self) -> crate::Codec {
3838
self.config.current_codec()
3939
}
40+
/// Returns reference to the remaining input data that has not been parsed.
41+
#[must_use]
42+
pub fn remaining(&self) -> &'input [u8] {
43+
self.input
44+
}
4045
/// Create a new [`Decoder`] from the given `input` and `config`.
4146
#[must_use]
4247
pub fn new(input: &'input [u8], config: DecoderOptions) -> Self {

src/cer.rs

+11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ pub fn decode<T: crate::Decode>(input: &[u8]) -> Result<T, crate::error::DecodeE
77
crate::ber::de::DecoderOptions::cer(),
88
))
99
}
10+
/// Attempts to decode `T` from `input` using CER. Returns both `T` and reference to the remainder of the input.
11+
///
12+
/// # Errors
13+
/// Returns `DecodeError` if `input` is not valid CER encoding specific to the expected type.
14+
pub fn decode_with_remainder<T: crate::Decode>(
15+
input: &[u8],
16+
) -> Result<(T, &[u8]), crate::error::DecodeError> {
17+
let decoder = &mut crate::ber::de::Decoder::new(input, crate::ber::de::DecoderOptions::cer());
18+
let decoded = T::decode(decoder)?;
19+
Ok((decoded, decoder.remaining()))
20+
}
1021

1122
/// Attempts to encode `value` to CER.
1223
pub fn encode<T: crate::Encode>(

src/codec.rs

+27
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,33 @@ impl Codec {
9595
),
9696
}
9797
}
98+
/// Decodes `input` to `D` based on the encoded defined by `Codec`, returning the decoded value and the remaining input.
99+
pub fn decode_from_binary_with_remainder<'input, D: Decode>(
100+
&self,
101+
input: &'input [u8],
102+
) -> Result<(D, &'input [u8]), crate::error::DecodeError> {
103+
match self {
104+
Self::Aper => crate::aper::decode_with_remainder(input),
105+
Self::Ber => crate::ber::decode_with_remainder(input),
106+
Self::Cer => crate::cer::decode_with_remainder(input),
107+
Self::Der => crate::der::decode_with_remainder(input),
108+
Self::Uper => crate::uper::decode_with_remainder(input),
109+
Self::Oer => crate::oer::decode_with_remainder(input),
110+
Self::Coer => crate::coer::decode_with_remainder(input),
111+
Self::Xer => Err(crate::error::DecodeError::from_kind(
112+
crate::error::DecodeErrorKind::Custom {
113+
msg: "XER does not support decoding with remainder. ".into(),
114+
},
115+
*self,
116+
)),
117+
Self::Jer => Err(crate::error::DecodeError::from_kind(
118+
crate::error::DecodeErrorKind::Custom {
119+
msg: "JER does not support decoding with remainder. ".into(),
120+
},
121+
*self,
122+
)),
123+
}
124+
}
98125

99126
/// Encodes a given value based on the value of `Codec`.
100127
/// This method shall be used when using text-based encoding rules.

src/de.rs

+98
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,104 @@ use crate::types::{self, AsnType, Constraints, Enumerated, SetOf, Tag};
99
pub use nom::Needed;
1010
pub use rasn_derive::Decode;
1111

12+
/// A generic ASN.1 decoding iterator. JER and XER are not supported.
13+
pub fn iter<D: Decode>(input: &[u8], codec: crate::codec::Codec) -> Iter<'_, D> {
14+
Iter::new(input, codec)
15+
}
16+
17+
/// Represents the input buffer in one of two states:
18+
/// - `Borrowed(&[u8])` for the original input slice.
19+
/// - `Owned { data: Vec<u8>, pos: usize }` after extra data has been appended.
20+
/// Here `pos` tracks how many bytes have been consumed.
21+
enum IterBuffer<'a> {
22+
Borrowed(&'a [u8]),
23+
Owned { data: Vec<u8>, pos: usize },
24+
}
25+
26+
impl IterBuffer<'_> {
27+
/// Returns the current unread portion of the data.
28+
fn as_slice(&self) -> &[u8] {
29+
match self {
30+
IterBuffer::Borrowed(slice) => slice,
31+
IterBuffer::Owned { data, pos } => &data[*pos..],
32+
}
33+
}
34+
/// Updates the buffer to account for the fact that `consumed` bytes were processed.
35+
fn update_after_consumption(&mut self, consumed: usize) {
36+
match self {
37+
IterBuffer::Borrowed(slice) => *slice = &slice[consumed..],
38+
IterBuffer::Owned { data, pos } => {
39+
*pos += consumed;
40+
// Drop the consumed bytes from the buffer once half of the data is already consumed.
41+
if *pos > data.len() / 2 {
42+
data.drain(0..*pos);
43+
*pos = 0;
44+
}
45+
}
46+
}
47+
}
48+
49+
/// Converts a Borrowed variant to an Owned one.
50+
#[allow(clippy::wrong_self_convention)]
51+
fn to_owned(&mut self) {
52+
if let IterBuffer::Borrowed(slice) = self {
53+
let vec = slice.to_vec();
54+
*self = IterBuffer::Owned { data: vec, pos: 0 };
55+
}
56+
}
57+
58+
/// Appends new bytes.
59+
///
60+
/// Internal buffer is in the Owned state from this point forward.
61+
fn extend(&mut self, bytes: &[u8]) {
62+
self.to_owned();
63+
if let IterBuffer::Owned { data, .. } = self {
64+
data.extend_from_slice(bytes);
65+
}
66+
}
67+
}
68+
69+
/// A generic ASN.1 decoding iterator.
70+
pub struct Iter<'input, D: Decode> {
71+
buf: IterBuffer<'input>,
72+
codec: crate::codec::Codec,
73+
_kind: core::marker::PhantomData<D>,
74+
}
75+
76+
impl<'input, D: Decode> Iter<'input, D> {
77+
/// Create a new iterator from a borrowed input slice.
78+
pub fn new(input: &'input [u8], codec: crate::codec::Codec) -> Self {
79+
Self {
80+
buf: IterBuffer::Borrowed(input),
81+
codec,
82+
_kind: core::marker::PhantomData,
83+
}
84+
}
85+
86+
/// Append new bytes to the input stream.
87+
/// After this call the iterator will switch to using an owned buffer.
88+
pub fn append_bytes(&mut self, bytes: &'input [u8]) {
89+
self.buf.extend(bytes);
90+
}
91+
}
92+
93+
impl<D: Decode> Iterator for Iter<'_, D> {
94+
type Item = Result<D, DecodeError>;
95+
96+
fn next(&mut self) -> Option<Self::Item> {
97+
let input = self.buf.as_slice();
98+
match self.codec.decode_from_binary_with_remainder(input) {
99+
Ok((value, remainder)) => {
100+
// Determine how many bytes were consumed.
101+
let consumed = input.len() - remainder.len();
102+
self.buf.update_after_consumption(consumed);
103+
Some(Ok(value))
104+
}
105+
Err(err) => Some(Err(err)),
106+
}
107+
}
108+
}
109+
12110
/// A **data type** that can decoded from any ASN.1 format.
13111
pub trait Decode: Sized + AsnType {
14112
/// Decode this value from a given ASN.1 decoder.

src/der.rs

+11
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ pub fn decode<T: crate::Decode>(input: &[u8]) -> Result<T, crate::error::DecodeE
99
crate::ber::de::DecoderOptions::der(),
1010
))
1111
}
12+
/// Attempts to decode `T` from `input` using DER. Returns both `T` and reference to the remainder of the input.
13+
///
14+
/// # Errors
15+
/// Returns `DecodeError` if `input` is not valid DER encoding specific to the expected type.
16+
pub fn decode_with_remainder<T: crate::Decode>(
17+
input: &[u8],
18+
) -> Result<(T, &[u8]), crate::error::DecodeError> {
19+
let decoder = &mut de::Decoder::new(input, de::DecoderOptions::der());
20+
let decoded = T::decode(decoder)?;
21+
Ok((decoded, decoder.remaining()))
22+
}
1223

1324
/// Attempts to encode `value` to DER.
1425
pub fn encode<T: crate::Encode>(

src/lib.rs

+33
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,37 @@ mod tests {
228228
round_trip(&Day::Tues);
229229
round_trip(&Day::Sat);
230230
}
231+
// Test iterator-based decoding
232+
#[test]
233+
fn decode_with_iterator() {
234+
use crate::types::Integer;
235+
236+
macro_rules! test_codec_iter {
237+
($codec:ident, $codec_enum:expr) => {
238+
let mut data = vec![];
239+
let integer_before1 = Integer::from(i64::from(i32::MIN) - 1);
240+
let integer_before2 = Integer::from(i64::from(i32::MAX) - 1);
241+
let integer_before3 = Integer::from(i64::from(i32::MIN) - i64::from(i16::MIN));
242+
data.extend(crate::$codec::encode(&integer_before1).unwrap());
243+
data.extend(crate::$codec::encode(&integer_before2).unwrap());
244+
let mut iter = crate::de::iter(&data, $codec_enum);
245+
let decoded: Integer = iter.next().unwrap().unwrap();
246+
assert_eq!(integer_before1, decoded);
247+
let int3_bytes = crate::$codec::encode(&integer_before3).unwrap();
248+
iter.append_bytes(&int3_bytes);
249+
let decoded: Integer = iter.next().unwrap().unwrap();
250+
assert_eq!(integer_before2, decoded);
251+
let decoded: Integer = iter.next().unwrap().unwrap();
252+
assert_eq!(integer_before3, decoded);
253+
};
254+
}
255+
256+
test_codec_iter!(oer, crate::Codec::Oer);
257+
test_codec_iter!(coer, crate::Codec::Coer);
258+
test_codec_iter!(uper, crate::Codec::Uper);
259+
test_codec_iter!(aper, crate::Codec::Aper);
260+
test_codec_iter!(ber, crate::Codec::Ber);
261+
test_codec_iter!(cer, crate::Codec::Cer);
262+
test_codec_iter!(der, crate::Codec::Der);
263+
}
231264
}

src/per.rs

+16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ pub(crate) fn decode<T: crate::Decode>(
2323
options,
2424
))
2525
}
26+
/// Attempts to decode `T` from `input` using PER. Returns both `T` and reference to the remainder of the input.
27+
///
28+
/// # Errors
29+
/// Returns `DecodeError` if `input` is not valid PER encoding specific to the expected type.
30+
pub(crate) fn decode_with_remainder<T: crate::Decode>(
31+
options: de::DecoderOptions,
32+
input: &[u8],
33+
) -> Result<(T, &[u8]), crate::error::DecodeError> {
34+
let decoder = &mut Decoder::<0, 0>::new(crate::types::BitStr::from_slice(input), options);
35+
let decoded = T::decode(decoder)?;
36+
let remaining_bits = decoder.input().len();
37+
// Consider only whole bytes, ignore padding bits
38+
let remaining_size = remaining_bits / 8;
39+
debug_assert!(input.len() >= remaining_size);
40+
Ok((decoded, &input[input.len() - remaining_size..]))
41+
}
2642

2743
/// Attempts to encode `value` to PER.
2844
pub(crate) fn encode<T: crate::Encode>(

src/per/de.rs

+18-18
Original file line numberDiff line numberDiff line change
@@ -276,12 +276,11 @@ impl<'input, const RFC: usize, const EFC: usize> Decoder<'input, RFC, EFC> {
276276
let range = if self.options.aligned && range > 256 {
277277
input = self.parse_padding(input)?;
278278
let range = crate::num::log2(range as i128);
279-
crate::bits::range_from_len(
279+
crate::bits::range_from_len(if range.is_power_of_two() {
280280
range
281-
.is_power_of_two()
282-
.then_some(range)
283-
.unwrap_or_else(|| range.next_power_of_two()),
284-
)
281+
} else {
282+
range.next_power_of_two()
283+
})
285284
} else {
286285
range as i128
287286
};
@@ -326,12 +325,11 @@ impl<'input, const RFC: usize, const EFC: usize> Decoder<'input, RFC, EFC> {
326325
let range = if self.options.aligned && range > 256 {
327326
input = self.parse_padding(input)?;
328327
let range = crate::num::log2(range as i128);
329-
crate::bits::range_from_len(
328+
crate::bits::range_from_len(if range.is_power_of_two() {
330329
range
331-
.is_power_of_two()
332-
.then_some(range)
333-
.unwrap_or_else(|| range.next_power_of_two()),
334-
)
330+
} else {
331+
range.next_power_of_two()
332+
})
335333
} else {
336334
range as i128
337335
};
@@ -586,10 +584,11 @@ impl<'input, const RFC: usize, const EFC: usize> Decoder<'input, RFC, EFC> {
586584
{
587585
let alphabet_width =
588586
crate::num::log2(alphabet.constraint.len() as i128);
589-
alphabet_width
590-
.is_power_of_two()
591-
.then_some(alphabet_width)
592-
.unwrap_or_else(|| alphabet_width.next_power_of_two())
587+
if alphabet_width.is_power_of_two() {
588+
alphabet_width
589+
} else {
590+
alphabet_width.next_power_of_two()
591+
}
593592
}
594593
} else {
595594
crate::num::log2(alphabet.constraint.len() as i128)
@@ -625,10 +624,11 @@ impl<'input, const RFC: usize, const EFC: usize> Decoder<'input, RFC, EFC> {
625624
bit_string,
626625
if self.options.aligned {
627626
{
628-
ALPHABET::CHARACTER_SET_WIDTH
629-
.is_power_of_two()
630-
.then_some(ALPHABET::CHARACTER_SET_WIDTH)
631-
.unwrap_or_else(|| ALPHABET::CHARACTER_SET_WIDTH.next_power_of_two())
627+
if ALPHABET::CHARACTER_SET_WIDTH.is_power_of_two() {
628+
ALPHABET::CHARACTER_SET_WIDTH
629+
} else {
630+
ALPHABET::CHARACTER_SET_WIDTH.next_power_of_two()
631+
}
632632
}
633633
} else {
634634
ALPHABET::CHARACTER_SET_WIDTH

0 commit comments

Comments
 (0)