Skip to main content

sentinel_driver/types/
bit.rs

1use bytes::{BufMut, BytesMut};
2
3use crate::error::{Error, Result};
4use crate::types::{FromSql, Oid, ToSql};
5
6/// PostgreSQL BIT / VARBIT type.
7///
8/// Stores a fixed- or variable-length bit string.
9/// `data` holds raw bytes (MSB-first, padded with trailing zeros in the last byte).
10/// `bit_length` is the actual number of significant bits.
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct PgBit {
13    pub data: Vec<u8>,
14    pub bit_length: i32,
15}
16
17impl PgBit {
18    /// Create from a slice of bools (true = 1, false = 0).
19    pub fn from_bools(bits: &[bool]) -> Self {
20        let bit_length = bits.len() as i32;
21        let byte_count = bits.len().div_ceil(8);
22        let mut data = vec![0u8; byte_count];
23
24        for (i, &bit) in bits.iter().enumerate() {
25            if bit {
26                data[i / 8] |= 1 << (7 - (i % 8));
27            }
28        }
29
30        PgBit { data, bit_length }
31    }
32
33    /// Get the bit at the given index (0-based, MSB-first).
34    pub fn get(&self, index: usize) -> Option<bool> {
35        if index >= self.bit_length as usize {
36            return None;
37        }
38        Some(self.data[index / 8] & (1 << (7 - (index % 8))) != 0)
39    }
40
41    /// Number of bits.
42    pub fn len(&self) -> usize {
43        self.bit_length as usize
44    }
45
46    /// True if zero bits.
47    pub fn is_empty(&self) -> bool {
48        self.bit_length == 0
49    }
50}
51
52impl ToSql for PgBit {
53    fn oid(&self) -> Oid {
54        Oid::VARBIT
55    }
56
57    fn to_sql(&self, buf: &mut BytesMut) -> Result<()> {
58        buf.put_i32(self.bit_length);
59        buf.put_slice(&self.data);
60        Ok(())
61    }
62}
63
64impl FromSql for PgBit {
65    fn oid() -> Oid {
66        Oid::VARBIT
67    }
68
69    fn from_sql(buf: &[u8]) -> Result<Self> {
70        if buf.len() < 4 {
71            return Err(Error::Decode(format!(
72                "bit: expected at least 4 bytes, got {}",
73                buf.len()
74            )));
75        }
76
77        let bit_length = i32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
78
79        if bit_length < 0 {
80            return Err(Error::Decode(format!(
81                "bit: negative bit length {bit_length}"
82            )));
83        }
84
85        let byte_count = (bit_length as usize).div_ceil(8);
86
87        if buf.len() < 4 + byte_count {
88            return Err(Error::Decode(format!(
89                "bit: expected {} data bytes for {} bits, got {}",
90                byte_count,
91                bit_length,
92                buf.len() - 4
93            )));
94        }
95
96        let data = buf[4..4 + byte_count].to_vec();
97
98        Ok(PgBit { data, bit_length })
99    }
100}