1#[cfg(feature = "diesel")]
2use crate::diesel_ext::bit::BitType;
3
4#[cfg(feature = "diesel")]
5use diesel::{deserialize::FromSqlRow, expression::AsExpression};
6
7#[derive(Clone, Debug, PartialEq, Eq)]
9#[cfg_attr(feature = "diesel", derive(FromSqlRow, AsExpression))]
10#[cfg_attr(feature = "diesel", diesel(sql_type = BitType))]
11pub struct Bit {
12 pub(crate) len: usize,
13 pub(crate) data: Vec<u8>,
14}
15
16impl Bit {
17 pub fn new(data: &[bool]) -> Bit {
19 let len = data.len();
20 let mut bytes = vec![0; (len + 7) / 8];
21 for (i, v) in data.iter().enumerate() {
22 bytes[i / 8] |= u8::from(*v) << (7 - (i % 8));
23 }
24 Bit { len, data: bytes }
25 }
26
27 pub fn from_bytes(data: &[u8]) -> Bit {
29 Bit {
30 len: data.len().checked_mul(8).unwrap(),
31 data: data.to_vec(),
32 }
33 }
34
35 pub fn len(&self) -> usize {
37 self.len
38 }
39
40 pub fn is_empty(&self) -> bool {
42 self.len == 0
43 }
44
45 pub fn as_bytes(&self) -> &[u8] {
47 self.data.as_slice()
48 }
49
50 #[cfg(any(feature = "postgres", feature = "sqlx", feature = "diesel"))]
51 pub(crate) fn from_sql(buf: &[u8]) -> Result<Bit, Box<dyn std::error::Error + Sync + Send>> {
52 let len = i32::from_be_bytes(buf[0..4].try_into()?).try_into()?;
53 let data = buf[4..4 + (len + 7) / 8].to_vec();
54
55 Ok(Bit { len, data })
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use crate::Bit;
62
63 #[test]
64 fn test_from_bytes() {
65 let vec = Bit::from_bytes(&[0b00000000, 0b11111111]);
66 assert_eq!(16, vec.len());
67 assert_eq!(&[0b00000000, 0b11111111], vec.as_bytes());
68 }
69
70 #[test]
71 fn test_as_bytes() {
72 let vec = Bit::new(&[true, false, true]);
73 assert_eq!(3, vec.len());
74 assert_eq!(&[0b10100000], vec.as_bytes());
75 }
76
77 #[test]
78 fn test_is_empty() {
79 let vec = Bit::new(&[]);
80 assert_eq!(0, vec.len());
81 assert!(vec.is_empty());
82 }
83}