1use crate::StorageType;
5use bincode::Options;
6use serde::Serialize;
7use std::ops::{Bound, RangeBounds};
8use std::path::Path;
9
10#[inline]
11pub fn be_fix_int_ser<S>(t: &S) -> Vec<u8>
12where
13 S: ?Sized + serde::Serialize,
14{
15 bincode::DefaultOptions::new()
16 .with_big_endian()
17 .with_fixint_encoding()
18 .serialize(t)
19 .expect("failed to serialize via be_fix_int_ser method")
20}
21
22#[inline]
25pub fn be_fix_int_ser_into<S>(buf: &mut Vec<u8>, t: &S) -> usize
26where
27 S: ?Sized + serde::Serialize,
28{
29 let before = buf.len();
30 bincode::DefaultOptions::new()
31 .with_big_endian()
32 .with_fixint_encoding()
33 .serialize_into(&mut *buf, t)
34 .expect("failed to serialize via be_fix_int_ser_into method");
35 buf.len() - before
36}
37
38pub(crate) fn iterator_bounds<K>(
39 lower_bound: Option<K>,
40 upper_bound: Option<K>,
41) -> (Option<Vec<u8>>, Option<Vec<u8>>)
42where
43 K: Serialize,
44{
45 (
46 lower_bound.map(|b| be_fix_int_ser(&b)),
47 upper_bound.map(|b| be_fix_int_ser(&b)),
48 )
49}
50
51pub(crate) fn iterator_bounds_with_range<K>(
52 range: impl RangeBounds<K>,
53) -> (Option<Vec<u8>>, Option<Vec<u8>>)
54where
55 K: Serialize,
56{
57 let iterator_lower_bound = match range.start_bound() {
58 Bound::Included(lower_bound) => {
59 Some(be_fix_int_ser(&lower_bound))
61 }
63 Bound::Excluded(lower_bound) => {
64 let mut key_buf = be_fix_int_ser(&lower_bound);
65
66 if is_max(&key_buf) {
67 key_buf.push(0);
72 } else {
73 big_endian_saturating_add_one(&mut key_buf);
75 }
76 Some(key_buf)
77 }
78 Bound::Unbounded => None,
79 };
80 let iterator_upper_bound = match range.end_bound() {
81 Bound::Included(upper_bound) => {
82 let mut key_buf = be_fix_int_ser(&upper_bound);
83
84 if is_max(&key_buf) {
85 None
89 } else {
90 big_endian_saturating_add_one(&mut key_buf);
93 Some(key_buf)
94 }
95 }
96 Bound::Excluded(upper_bound) => {
97 Some(be_fix_int_ser(&upper_bound))
99 }
101 Bound::Unbounded => None,
102 };
103 (iterator_lower_bound, iterator_upper_bound)
104}
105
106fn big_endian_saturating_add_one(v: &mut [u8]) {
110 if is_max(v) {
111 return;
112 }
113 for i in (0..v.len()).rev() {
114 if v[i] == u8::MAX {
115 v[i] = 0;
116 } else {
117 v[i] += 1;
118 break;
119 }
120 }
121}
122
123fn is_max(v: &[u8]) -> bool {
125 v.iter().all(|&x| x == u8::MAX)
126}
127
128pub(crate) fn ensure_database_type<P: AsRef<Path>>(
129 path: P,
130 storage_type: StorageType,
131) -> std::io::Result<()> {
132 if !path.as_ref().exists() {
133 return Ok(());
134 }
135 for entry in std::fs::read_dir(path)? {
136 let filepath = entry?.path();
137 if filepath.extension().is_some_and(|ext| ext == "sst")
138 && storage_type != StorageType::Rocks
139 {
140 panic!(
141 "DB type mismatch: expected {:?}, found RocksDB",
142 storage_type
143 );
144 }
145 if filepath
146 .file_name()
147 .is_some_and(|n| n.to_string_lossy().starts_with("wal_"))
148 && storage_type != StorageType::TideHunter
149 {
150 panic!(
151 "DB type mismatch: expected {:?}, found TideHunter",
152 storage_type
153 );
154 }
155 }
156 Ok(())
157}
158
159#[allow(
160 clippy::assign_op_pattern,
161 clippy::manual_div_ceil,
162 clippy::disallowed_methods
163)] #[test]
165fn test_helpers() {
166 let v = vec![];
167 assert!(is_max(&v));
168
169 fn check_add(v: Vec<u8>) {
170 let mut v = v;
171 let num = Num32::from_big_endian(&v);
172 big_endian_saturating_add_one(&mut v);
173 assert!(num + 1 == Num32::from_big_endian(&v));
174 }
175
176 uint::construct_uint! {
177 struct Num32(4);
179 }
180
181 let mut v = vec![255; 32];
182 big_endian_saturating_add_one(&mut v);
183 assert!(Num32::MAX == Num32::from_big_endian(&v));
184
185 check_add(vec![1; 32]);
186 check_add(vec![6; 32]);
187 check_add(vec![254; 32]);
188
189 }