Skip to content

Commit

Permalink
fix: FixedBitString might work as expected (#385)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicceboy authored Nov 28, 2024
1 parent 37a93d3 commit 2bab0e3
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 11 deletions.
39 changes: 33 additions & 6 deletions src/types/strings/bit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,28 @@ use crate::prelude::*;
/// ```
pub type BitString = bitvec::vec::BitVec<u8, bitvec::order::Msb0>;
/// A fixed length `BIT STRING` type.
///
/// IMPORTANT: While N describes the number of bits, also the internal size is for N amount of bytes.
/// When accessing the bits, use &array[..N] to get the correct bits, for example.
/// Also when setting the bits, you should use the big-endian ordering. See example.
/// Constraints are checked for N amount of bits and encoding operation will drop extra bits since the underlying container is larger.
///
/// # Example
/// ```rust
/// use rasn::prelude::*;
/// use bitvec::prelude::*;
///
/// let bool_array = [true, false, true];
/// let mut bit_array: FixedBitString<3> = BitArray::ZERO;
/// for (i, &value) in bool_array.iter().enumerate() {
/// bit_array.set(i, value);
/// }
/// // Also works: (note that the first byte can hold the whole bit array, since N = 3)
/// let second_array = FixedBitString::<3>::new([0b10100000, 0, 0]);
/// assert_eq!(bit_array, second_array);
/// ```
pub type FixedBitString<const N: usize> = bitvec::array::BitArray<[u8; N], bitvec::order::Msb0>;

/// A reference to a `BIT STRING` type.
pub type BitStr = bitvec::slice::BitSlice<u8, bitvec::order::Msb0>;

Expand Down Expand Up @@ -62,6 +83,7 @@ impl Encode for BitStr {

impl<const N: usize> AsnType for FixedBitString<N> {
const TAG: Tag = Tag::BIT_STRING;
const CONSTRAINTS: Constraints = constraints!(size_constraint!(N));
}

impl<const N: usize> Decode for FixedBitString<N> {
Expand All @@ -71,14 +93,17 @@ impl<const N: usize> Decode for FixedBitString<N> {
constraints: Constraints,
) -> Result<Self, D::Error> {
let out = decoder.decode_bit_string(tag, constraints)?;
out.as_bitslice().try_into().map_err(|_| {
D::Error::from(DecodeError::fixed_string_conversion_failed(
if out.len() != N {
return Err(D::Error::from(DecodeError::fixed_string_conversion_failed(
Tag::BIT_STRING,
out.as_bitslice().len(),
out.len(),
N,
decoder.codec(),
))
})
)));
}
let mut array = Self::ZERO;
array[..out.len()].copy_from_bitslice(&out);
Ok(array)
}
}

Expand All @@ -89,6 +114,8 @@ impl<const N: usize> Encode for FixedBitString<N> {
tag: Tag,
constraints: Constraints,
) -> Result<(), E::Error> {
encoder.encode_bit_string(tag, constraints, self).map(drop)
encoder
.encode_bit_string(tag, constraints, &self[..N])
.map(drop)
}
}
35 changes: 30 additions & 5 deletions tests/strings.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Test whether constrained OctetString and FixedOctetString are equal
use bitvec::prelude::*;
use rasn::prelude::*;
use rasn::{ber, jer, oer, uper};

Expand All @@ -19,17 +20,23 @@ pub struct Hashes {
#[derive(AsnType, Decode, Encode, Debug, Clone, PartialEq)]
#[rasn(automatic_tags)]
pub struct ConstrainedHashes {
#[rasn(size("3"))]
pub hashed3: FixedOctetString<3>,
#[rasn(size("8"))]
pub hashed8: FixedOctetString<8>,
#[rasn(size("16"))]
pub hashed16: FixedOctetString<16>,
#[rasn(size("32"))]
pub hashed32: FixedOctetString<32>,
#[rasn(size("64"))]
pub hashed64: FixedOctetString<64>,
}
#[derive(AsnType, Decode, Encode, Debug, Clone, PartialEq)]
#[rasn(automatic_tags)]
pub struct ConstrainedFixBitString {
pub hashed3: FixedBitString<3>,
}
#[derive(AsnType, Decode, Encode, Debug, Clone, PartialEq)]
#[rasn(automatic_tags)]
pub struct ConstrainedBitString {
#[rasn(size("3"))]
pub hashed3: BitString,
}

fn build_octet() -> Hashes {
Hashes {
Expand Down Expand Up @@ -92,6 +99,24 @@ macro_rules! test_decode_eq {
let encoded_fixed = $codec::encode(&fixed_items).unwrap();
let decoded = $codec::decode::<Hashes>(&encoded).unwrap();
let decoded_fixed = $codec::decode::<ConstrainedHashes>(&encoded_fixed).unwrap();
let bits = BitString::from_bitslice(&BitVec::<u8, Msb0>::repeat(true, 3));
let bs = ConstrainedBitString {
hashed3: BitString::from(bits),
};
let bool_array = [true, true, true];
let mut bit_array: BitArray<[u8; 3], Msb0> = BitArray::ZERO;
for (i, &value) in bool_array.iter().enumerate() {
bit_array.set(i, value);
}
let bs_fixed = ConstrainedFixBitString { hashed3: bit_array };
let encoded_bs = $codec::encode(&bs).unwrap();
let encoded_bs_fixed = $codec::encode(&bs_fixed).unwrap();
let decoded_bs = $codec::decode::<ConstrainedBitString>(&encoded_bs).unwrap();
let decoded_bs_fixed =
$codec::decode::<ConstrainedFixBitString>(&encoded_bs_fixed).unwrap();
assert_eq!(bs, decoded_bs);
assert_eq!(encoded_bs, encoded_bs_fixed);
assert_eq!(bs_fixed, decoded_bs_fixed);
assert_eq!(items, decoded);
assert_eq!(encoded, encoded_fixed);
assert_eq!(fixed_items, decoded_fixed);
Expand Down

0 comments on commit 2bab0e3

Please sign in to comment.