darkfi_sdk/monotree/
bits.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 * Copyright (C) 2021 MONOLOG (Taeho Francis Lim and Jongwhan Lee) MIT License
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20use std::{cmp::Ordering, ops::Range};
21
22use super::{
23    utils::{bit, bytes_to_int, len_lcp, offsets},
24    BitsLen,
25};
26use crate::GenericResult;
27
28/// `BitVec` implementation based on bytes slice.
29#[derive(Debug, Clone)]
30pub struct Bits<'a> {
31    pub path: &'a [u8],
32    pub range: Range<BitsLen>,
33}
34
35impl<'a> Bits<'a> {
36    pub fn new(bytes: &'a [u8]) -> Self {
37        Self { path: bytes, range: 0..(bytes.len() as BitsLen * 8) }
38    }
39
40    /// Construct `Bits` instance by deserializing bytes slice.
41    pub fn from_bytes(bytes: &'a [u8]) -> Self {
42        let u = std::mem::size_of::<BitsLen>();
43        let start: BitsLen = bytes_to_int(&bytes[..u]);
44        let end: BitsLen = bytes_to_int(&bytes[u..2 * u]);
45        Self { path: &bytes[2 * u..], range: start..end }
46    }
47
48    /// Serialize `Bits` into bytes.
49    pub fn to_bytes(&self) -> GenericResult<Vec<u8>> {
50        Ok([&self.range.start.to_be_bytes(), &self.range.end.to_be_bytes(), self.path].concat())
51    }
52
53    /// Get the very first bit.
54    pub fn first(&self) -> bool {
55        bit(self.path, self.range.start)
56    }
57
58    pub fn len(&self) -> BitsLen {
59        self.range.end - self.range.start
60    }
61
62    pub fn is_empty(&self) -> bool {
63        self.len() == 0 || self.path.len() == 0
64    }
65
66    /// Get the resulting `Bits` when shifted with the given size.
67    pub fn shift(&self, n: BitsLen, tail: bool) -> Self {
68        let (q, range) = offsets(&self.range, n, tail);
69        if tail {
70            Self { path: &self.path[..q as usize], range }
71        } else {
72            Self { path: &self.path[q as usize..], range }
73        }
74    }
75
76    /// Get length of the longest common prefix bits for the given two `Bits`.
77    pub fn len_common_bits(a: &Self, b: &Self) -> BitsLen {
78        len_lcp(a.path, &a.range, b.path, &b.range)
79    }
80
81    /// Get the bit at position `i` within this Bits range
82    pub fn bit(&self, i: BitsLen) -> bool {
83        assert!(i < self.len(), "Bit index out of range");
84        bit(self.path, self.range.start + i)
85    }
86
87    /// Compare bits lexicographically (MSB to LSB)
88    pub fn lexical_cmp(&self, other: &Self) -> Ordering {
89        let min_len = std::cmp::min(self.len(), other.len());
90
91        // Compare bit by bit from start of range
92        for i in 0..min_len {
93            match (self.bit(i), other.bit(i)) {
94                (false, true) => return Ordering::Less,
95                (true, false) => return Ordering::Greater,
96                _ => continue,
97            }
98        }
99
100        // All compared bits equal, compare lengths
101        self.len().cmp(&other.len())
102    }
103}
104
105// Implement equality/ordering based on actual bit values
106impl PartialEq for Bits<'_> {
107    fn eq(&self, other: &Self) -> bool {
108        self.len() == other.len() && (0..self.len()).all(|i| self.bit(i) == other.bit(i))
109    }
110}
111
112impl Eq for Bits<'_> {}
113
114#[allow(clippy::non_canonical_partial_ord_impl)]
115impl PartialOrd for Bits<'_> {
116    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
117        Some(self.lexical_cmp(other))
118    }
119}
120
121impl Ord for Bits<'_> {
122    fn cmp(&self, other: &Self) -> Ordering {
123        self.lexical_cmp(other)
124    }
125}