asn1_rs/asn1_types/
bitstring.rs1use crate::*;
2use alloc::borrow::Cow;
3#[cfg(feature = "bits")]
4use bitvec::{order::Msb0, slice::BitSlice};
5use core::convert::TryFrom;
6
7#[derive(Clone, Debug, Eq, PartialEq)]
9pub struct BitString<'a> {
10 pub unused_bits: u8,
11 pub data: Cow<'a, [u8]>,
12}
13
14impl<'a> BitString<'a> {
15 pub const fn new(unused_bits: u8, s: &'a [u8]) -> Self {
17 BitString {
18 unused_bits,
19 data: Cow::Borrowed(s),
20 }
21 }
22
23 pub fn is_set(&self, bitnum: usize) -> bool {
25 let byte_pos = bitnum / 8;
26 if byte_pos >= self.data.len() {
27 return false;
28 }
29 let b = 7 - (bitnum % 8);
30 (self.data[byte_pos] & (1 << b)) != 0
31 }
32
33 #[cfg(feature = "bits")]
35 pub fn as_bitslice(&self) -> Option<&BitSlice<u8, Msb0>> {
36 BitSlice::<_, Msb0>::try_from_slice(&self.data).ok()
37 }
38}
39
40impl<'a> AsRef<[u8]> for BitString<'a> {
41 fn as_ref(&self) -> &[u8] {
42 &self.data
43 }
44}
45
46impl<'a> TryFrom<Any<'a>> for BitString<'a> {
47 type Error = Error;
48
49 fn try_from(any: Any<'a>) -> Result<BitString<'a>> {
50 TryFrom::try_from(&any)
51 }
52}
53
54impl<'a, 'b> TryFrom<&'b Any<'a>> for BitString<'a> {
56 type Error = Error;
57
58 fn try_from(any: &'b Any<'a>) -> Result<BitString<'a>> {
59 any.tag().assert_eq(Self::TAG)?;
60 if any.data.is_empty() {
61 return Err(Error::InvalidLength);
62 }
63 let s = any.data;
64 let (unused_bits, data) = (s[0], Cow::Borrowed(&s[1..]));
65 Ok(BitString { unused_bits, data })
66 }
67}
68
69impl<'a> CheckDerConstraints for BitString<'a> {
70 fn check_constraints(any: &Any) -> Result<()> {
71 any.header.assert_primitive()?;
73 match any.data.len() {
75 0 => Err(Error::InvalidLength),
76 1 => {
77 if any.data[0] == 0 {
79 Ok(())
80 } else {
81 Err(Error::InvalidLength)
82 }
83 }
84 len => {
85 let unused_bits = any.data[0];
86 let last_byte = any.data[len - 1];
87 if last_byte.trailing_zeros() < unused_bits as u32 {
88 return Err(Error::DerConstraintFailed(DerConstraint::UnusedBitsNotZero));
89 }
90
91 Ok(())
92 }
93 }
94 }
95}
96
97impl DerAutoDerive for BitString<'_> {}
98
99impl<'a> Tagged for BitString<'a> {
100 const TAG: Tag = Tag::BitString;
101}
102
103#[cfg(feature = "std")]
104impl ToDer for BitString<'_> {
105 fn to_der_len(&self) -> Result<usize> {
106 let sz = self.data.len();
107 if sz < 127 {
108 Ok(3 + sz)
110 } else {
111 let n = Length::Definite(sz + 1).to_der_len()?;
113 Ok(2 + n + sz)
114 }
115 }
116
117 fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
118 let header = Header::new(
119 Class::Universal,
120 false,
121 Self::TAG,
122 Length::Definite(1 + self.data.len()),
123 );
124 header.write_der_header(writer).map_err(Into::into)
125 }
126
127 fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
128 let sz = writer.write(&[self.unused_bits])?;
129 let sz = sz + writer.write(&self.data)?;
130 Ok(sz)
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::BitString;
137
138 #[test]
139 fn test_bitstring_is_set() {
140 let obj = BitString::new(0, &[0x0f, 0x00, 0x40]);
141 assert!(!obj.is_set(0));
142 assert!(obj.is_set(7));
143 assert!(!obj.is_set(9));
144 assert!(obj.is_set(17));
145 }
146
147 #[cfg(feature = "bits")]
148 #[test]
149 fn test_bitstring_to_bitvec() {
150 let obj = BitString::new(0, &[0x0f, 0x00, 0x40]);
151 let bv = obj.as_bitslice().expect("could not get bitslice");
152 assert_eq!(bv.get(0).as_deref(), Some(&false));
153 assert_eq!(bv.get(7).as_deref(), Some(&true));
154 assert_eq!(bv.get(9).as_deref(), Some(&false));
155 assert_eq!(bv.get(17).as_deref(), Some(&true));
156 }
157}