bitstring/
bit_length_string.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use core::cmp::{
	min,
	Ordering,
};

use crate::{
	bit_string::BitString,
	FixedBitString,
};

/// Extend a
/// [`FixedBitString`](fixed_bit_string/trait.FixedBitString.html) to a
/// [`BitString`](bit_string/trait.BitString.html) by also storing a
/// length.
#[derive(Clone, Debug, Hash)]
// TODO: drop the PartialEq + Eq manual implementations; instead require
// the underyling type to implement sane semantics (i.e. not contain any
// data outside what is accessible through "FixedBitString")
#[allow(clippy::derived_hash_with_manual_eq)]
pub struct BitLengthString<W: FixedBitString> {
	/// underlying bit string with fixed length
	bits: W,
	/// current length of [`BitString`](trait.BitString.html); should
	/// not exceed [`W::len()`](trait.FixedBitString.html#tymethod.len).
	len: usize,
}

impl<W: FixedBitString> BitLengthString<W> {
	/// Create new dynamic-length bit string from fixed bit string and a
	/// length.
	///
	/// The bits in `bits` after `len` bits are set to false.
	///
	/// # Panics
	///
	/// Panics if `len > W::len()`.
	pub fn new(mut bits: W, len: usize) -> Self {
		assert!(len <= W::LEN);
		bits.set_false_from(len);
		BitLengthString { bits, len }
	}

	/// check whether another bit string `bits` is prefixed by `self`
	pub fn contains(&self, bits: &W) -> bool {
		self.bits.contains(self.len, bits)
	}

	/// get read access to the bits
	pub fn bits(&self) -> &W {
		&self.bits
	}

	/// length of bit string (same as
	/// [`BitString::len()`](bit_string/trait.BitString.html#tymethod.len))
	#[allow(clippy::len_without_is_empty)]
	pub fn len(&self) -> usize {
		self.len
	}
}

impl<W: FixedBitString> BitString for BitLengthString<W> {
	fn get(&self, ndx: usize) -> bool {
		assert!(ndx < self.len);
		self.bits.get(ndx)
	}

	fn set(&mut self, ndx: usize, bit: bool) {
		assert!(ndx < self.len);
		self.bits.set(ndx, bit);
	}

	fn flip(&mut self, ndx: usize) {
		assert!(ndx < self.len);
		self.bits.flip(ndx);
	}

	fn len(&self) -> usize {
		debug_assert!(self.len <= W::LEN);
		self.len
	}

	fn clip(&mut self, len: usize) {
		self.bits.set_false_from(len);
		self.len = min(self.len, len);
	}

	fn append(&mut self, bit: bool) {
		self.bits.set(self.len, bit);
		self.len += 1;
	}

	fn null() -> Self {
		BitLengthString {
			bits: W::new_all_false(),
			len: 0,
		}
	}

	fn shared_prefix_len(&self, other: &Self) -> usize {
		let max_len = min(self.len, other.len);
		min(W::shared_prefix_len(&self.bits, &other.bits), max_len)
	}
}

impl<W: FixedBitString> Default for BitLengthString<W> {
	fn default() -> Self {
		Self::null()
	}
}

impl<W: FixedBitString> Ord for BitLengthString<W> {
	fn cmp(&self, rhs: &Self) -> Ordering {
		self.lexicographic_cmp(rhs)
	}
}
impl<W: FixedBitString> PartialOrd for BitLengthString<W> {
	fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
		Some(self.cmp(rhs))
	}
}

// TODO: we derive `Hash`, so we probably could derive this too
impl<W: FixedBitString> PartialEq for BitLengthString<W> {
	fn eq(&self, rhs: &Self) -> bool {
		Ordering::Equal == self.cmp(rhs)
	}
}
impl<W: FixedBitString> Eq for BitLengthString<W> {}