use crate::*;
use alloc::borrow::Cow;
#[cfg(feature = "bits")]
use bitvec::{order::Msb0, slice::BitSlice};
use core::convert::TryFrom;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BitString<'a> {
pub unused_bits: u8,
pub data: Cow<'a, [u8]>,
}
impl<'a> BitString<'a> {
pub const fn new(unused_bits: u8, s: &'a [u8]) -> Self {
BitString {
unused_bits,
data: Cow::Borrowed(s),
}
}
pub fn is_set(&self, bitnum: usize) -> bool {
let byte_pos = bitnum / 8;
if byte_pos >= self.data.len() {
return false;
}
let b = 7 - (bitnum % 8);
(self.data[byte_pos] & (1 << b)) != 0
}
#[cfg(feature = "bits")]
pub fn as_bitslice(&self) -> Option<&BitSlice<u8, Msb0>> {
BitSlice::<_, Msb0>::try_from_slice(&self.data).ok()
}
}
impl<'a> AsRef<[u8]> for BitString<'a> {
fn as_ref(&self) -> &[u8] {
&self.data
}
}
impl<'a> TryFrom<Any<'a>> for BitString<'a> {
type Error = Error;
fn try_from(any: Any<'a>) -> Result<BitString<'a>> {
TryFrom::try_from(&any)
}
}
impl<'a, 'b> TryFrom<&'b Any<'a>> for BitString<'a> {
type Error = Error;
fn try_from(any: &'b Any<'a>) -> Result<BitString<'a>> {
any.tag().assert_eq(Self::TAG)?;
if any.data.is_empty() {
return Err(Error::InvalidLength);
}
let s = any.data;
let (unused_bits, data) = (s[0], Cow::Borrowed(&s[1..]));
Ok(BitString { unused_bits, data })
}
}
impl<'a> CheckDerConstraints for BitString<'a> {
fn check_constraints(any: &Any) -> Result<()> {
any.header.assert_primitive()?;
match any.data.len() {
0 => Err(Error::InvalidLength),
1 => {
if any.data[0] == 0 {
Ok(())
} else {
Err(Error::InvalidLength)
}
}
len => {
let unused_bits = any.data[0];
let last_byte = any.data[len - 1];
if last_byte.trailing_zeros() < unused_bits as u32 {
return Err(Error::DerConstraintFailed(DerConstraint::UnusedBitsNotZero));
}
Ok(())
}
}
}
}
impl DerAutoDerive for BitString<'_> {}
impl<'a> Tagged for BitString<'a> {
const TAG: Tag = Tag::BitString;
}
#[cfg(feature = "std")]
impl ToDer for BitString<'_> {
fn to_der_len(&self) -> Result<usize> {
let sz = self.data.len();
if sz < 127 {
Ok(3 + sz)
} else {
let n = Length::Definite(sz + 1).to_der_len()?;
Ok(2 + n + sz)
}
}
fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
let header = Header::new(
Class::Universal,
false,
Self::TAG,
Length::Definite(1 + self.data.len()),
);
header.write_der_header(writer).map_err(Into::into)
}
fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
let sz = writer.write(&[self.unused_bits])?;
let sz = sz + writer.write(&self.data)?;
Ok(sz)
}
}
#[cfg(test)]
mod tests {
use super::BitString;
#[test]
fn test_bitstring_is_set() {
let obj = BitString::new(0, &[0x0f, 0x00, 0x40]);
assert!(!obj.is_set(0));
assert!(obj.is_set(7));
assert!(!obj.is_set(9));
assert!(obj.is_set(17));
}
#[cfg(feature = "bits")]
#[test]
fn test_bitstring_to_bitvec() {
let obj = BitString::new(0, &[0x0f, 0x00, 0x40]);
let bv = obj.as_bitslice().expect("could not get bitslice");
assert_eq!(bv.get(0).as_deref(), Some(&false));
assert_eq!(bv.get(7).as_deref(), Some(&true));
assert_eq!(bv.get(9).as_deref(), Some(&false));
assert_eq!(bv.get(17).as_deref(), Some(&true));
}
}