1mod directory_layer;
63mod directory_partition;
64mod directory_subspace;
65mod error;
66mod node;
67
68use crate::tuple::{PackResult, Subspace, TuplePack, TupleUnpack};
69use crate::Transaction;
70use async_trait::async_trait;
71use core::cmp;
72pub use directory_layer::DirectoryLayer;
73pub use directory_partition::DirectoryPartition;
74pub use directory_subspace::DirectorySubspace;
75pub use error::DirectoryError;
76use std::cmp::Ordering;
77
78#[async_trait]
90pub trait Directory {
91 async fn create_or_open(
97 &self,
98 txn: &Transaction,
99 path: &[String],
100 prefix: Option<&[u8]>,
101 layer: Option<&[u8]>,
102 ) -> Result<DirectoryOutput, DirectoryError>;
103
104 async fn create(
110 &self,
111 txn: &Transaction,
112 path: &[String],
113 prefix: Option<&[u8]>,
114 layer: Option<&[u8]>,
115 ) -> Result<DirectoryOutput, DirectoryError>;
116
117 async fn open(
119 &self,
120 txn: &Transaction,
121 path: &[String],
122 layer: Option<&[u8]>,
123 ) -> Result<DirectoryOutput, DirectoryError>;
124
125 async fn exists(&self, trx: &Transaction, path: &[String]) -> Result<bool, DirectoryError>;
127
128 async fn move_directory(
130 &self,
131 trx: &Transaction,
132 new_path: &[String],
133 ) -> Result<DirectoryOutput, DirectoryError>;
134
135 async fn move_to(
137 &self,
138 trx: &Transaction,
139 old_path: &[String],
140 new_path: &[String],
141 ) -> Result<DirectoryOutput, DirectoryError>;
142
143 async fn remove(&self, trx: &Transaction, path: &[String]) -> Result<bool, DirectoryError>;
145
146 async fn remove_if_exists(
148 &self,
149 trx: &Transaction,
150 path: &[String],
151 ) -> Result<bool, DirectoryError>;
152
153 async fn list(&self, trx: &Transaction, path: &[String])
155 -> Result<Vec<String>, DirectoryError>;
156}
157
158pub(crate) fn compare_slice<T: Ord>(a: &[T], b: &[T]) -> cmp::Ordering {
159 for (ai, bi) in a.iter().zip(b.iter()) {
160 match ai.cmp(bi) {
161 Ordering::Equal => continue,
162 ord => return ord,
163 }
164 }
165
166 a.len().cmp(&b.len())
168}
169
170#[derive(Clone, Debug)]
172pub enum DirectoryOutput {
173 DirectorySubspace(DirectorySubspace),
175 DirectoryPartition(DirectoryPartition),
177}
178
179impl DirectoryOutput {
180 pub fn subspace<T: TuplePack>(&self, t: &T) -> Result<Subspace, DirectoryError> {
181 match self {
182 DirectoryOutput::DirectorySubspace(d) => Ok(d.subspace(t)),
183 DirectoryOutput::DirectoryPartition(_) => {
184 Err(DirectoryError::CannotOpenDirectoryPartition)
185 }
186 }
187 }
188
189 pub fn bytes(&self) -> Result<&[u8], DirectoryError> {
190 match self {
191 DirectoryOutput::DirectorySubspace(d) => Ok(d.bytes()),
192 DirectoryOutput::DirectoryPartition(_) => {
193 Err(DirectoryError::CannotOpenDirectoryPartition)
194 }
195 }
196 }
197
198 pub fn pack<T: TuplePack>(&self, t: &T) -> Result<Vec<u8>, DirectoryError> {
199 match self {
200 DirectoryOutput::DirectorySubspace(d) => Ok(d.pack(t)),
201 DirectoryOutput::DirectoryPartition(_) => {
202 Err(DirectoryError::CannotPackDirectoryPartition)
203 }
204 }
205 }
206
207 pub fn unpack<'de, T: TupleUnpack<'de>>(
208 &self,
209 key: &'de [u8],
210 ) -> Result<PackResult<T>, DirectoryError> {
211 match self {
212 DirectoryOutput::DirectorySubspace(d) => Ok(d.unpack(key)),
213 DirectoryOutput::DirectoryPartition(_) => {
214 Err(DirectoryError::CannotPackDirectoryPartition)
215 }
216 }
217 }
218
219 pub fn range(&self) -> Result<(Vec<u8>, Vec<u8>), DirectoryError> {
220 match self {
221 DirectoryOutput::DirectorySubspace(d) => Ok(d.range()),
222 DirectoryOutput::DirectoryPartition(_) => {
223 Err(DirectoryError::CannotRangeDirectoryPartition)
224 }
225 }
226 }
227
228 pub fn get_path(&self) -> &[String] {
229 match self {
230 DirectoryOutput::DirectorySubspace(d) => d.get_path(),
231 DirectoryOutput::DirectoryPartition(d) => d.get_path(),
232 }
233 }
234
235 pub fn get_layer(&self) -> &[u8] {
236 match self {
237 DirectoryOutput::DirectorySubspace(d) => d.get_layer(),
238 DirectoryOutput::DirectoryPartition(d) => d.get_layer(),
239 }
240 }
241}
242
243#[async_trait]
244impl Directory for DirectoryOutput {
245 async fn create_or_open(
246 &self,
247 txn: &Transaction,
248 path: &[String],
249 prefix: Option<&[u8]>,
250 layer: Option<&[u8]>,
251 ) -> Result<DirectoryOutput, DirectoryError> {
252 match self {
253 DirectoryOutput::DirectorySubspace(d) => {
254 d.create_or_open(txn, path, prefix, layer).await
255 }
256 DirectoryOutput::DirectoryPartition(d) => {
257 d.create_or_open(txn, path, prefix, layer).await
258 }
259 }
260 }
261
262 async fn create(
263 &self,
264 txn: &Transaction,
265 path: &[String],
266 prefix: Option<&[u8]>,
267 layer: Option<&[u8]>,
268 ) -> Result<DirectoryOutput, DirectoryError> {
269 match self {
270 DirectoryOutput::DirectorySubspace(d) => d.create(txn, path, prefix, layer).await,
271 DirectoryOutput::DirectoryPartition(d) => d.create(txn, path, prefix, layer).await,
272 }
273 }
274
275 async fn open(
276 &self,
277 txn: &Transaction,
278 path: &[String],
279 layer: Option<&[u8]>,
280 ) -> Result<DirectoryOutput, DirectoryError> {
281 match self {
282 DirectoryOutput::DirectorySubspace(d) => d.open(txn, path, layer).await,
283 DirectoryOutput::DirectoryPartition(d) => d.open(txn, path, layer).await,
284 }
285 }
286
287 async fn exists(&self, trx: &Transaction, path: &[String]) -> Result<bool, DirectoryError> {
288 match self {
289 DirectoryOutput::DirectorySubspace(d) => d.exists(trx, path).await,
290 DirectoryOutput::DirectoryPartition(d) => d.exists(trx, path).await,
291 }
292 }
293
294 async fn move_directory(
295 &self,
296 trx: &Transaction,
297 new_path: &[String],
298 ) -> Result<DirectoryOutput, DirectoryError> {
299 match self {
300 DirectoryOutput::DirectorySubspace(d) => d.move_directory(trx, new_path).await,
301 DirectoryOutput::DirectoryPartition(d) => d.move_directory(trx, new_path).await,
302 }
303 }
304
305 async fn move_to(
306 &self,
307 trx: &Transaction,
308 old_path: &[String],
309 new_path: &[String],
310 ) -> Result<DirectoryOutput, DirectoryError> {
311 match self {
312 DirectoryOutput::DirectorySubspace(d) => d.move_to(trx, old_path, new_path).await,
313 DirectoryOutput::DirectoryPartition(d) => d.move_to(trx, old_path, new_path).await,
314 }
315 }
316
317 async fn remove(&self, trx: &Transaction, path: &[String]) -> Result<bool, DirectoryError> {
318 match self {
319 DirectoryOutput::DirectorySubspace(d) => d.remove(trx, path).await,
320 DirectoryOutput::DirectoryPartition(d) => d.remove(trx, path).await,
321 }
322 }
323
324 async fn remove_if_exists(
325 &self,
326 trx: &Transaction,
327 path: &[String],
328 ) -> Result<bool, DirectoryError> {
329 match self {
330 DirectoryOutput::DirectorySubspace(d) => d.remove_if_exists(trx, path).await,
331 DirectoryOutput::DirectoryPartition(d) => d.remove_if_exists(trx, path).await,
332 }
333 }
334
335 async fn list(
336 &self,
337 trx: &Transaction,
338 path: &[String],
339 ) -> Result<Vec<String>, DirectoryError> {
340 match self {
341 DirectoryOutput::DirectorySubspace(d) => d.list(trx, path).await,
342 DirectoryOutput::DirectoryPartition(d) => d.list(trx, path).await,
343 }
344 }
345}
346
347pub(crate) fn strinc(key: Vec<u8>) -> Vec<u8> {
349 let mut key = key;
350
351 for i in (0..key.len()).rev() {
352 if key[i] != 0xff {
353 key[i] += 1;
354 break;
355 } else {
356 key.remove(i);
358 }
359 }
360 key
361}
362
363#[cfg(test)]
364mod tests {
365 use super::*;
366
367 #[test]
369 fn test_strinc() {
370 assert_eq!(strinc(Vec::from("a".as_bytes())), Vec::from("b".as_bytes()));
371 assert_eq!(strinc(Vec::from("y".as_bytes())), Vec::from("z".as_bytes()));
372 assert_eq!(
373 strinc(Vec::from("!".as_bytes())),
374 Vec::from("\"".as_bytes())
375 );
376 assert_eq!(strinc(Vec::from("*".as_bytes())), Vec::from("+".as_bytes()));
377 assert_eq!(
378 strinc(Vec::from("fdb".as_bytes())),
379 Vec::from("fdc".as_bytes())
380 );
381 assert_eq!(
382 strinc(Vec::from("foundation database 6".as_bytes())),
383 Vec::from("foundation database 7".as_bytes())
384 );
385
386 assert_eq!(strinc(vec![61u8, 62u8, 255u8]), vec![61u8, 63u8]);
387 assert_eq!(strinc(vec![253u8, 255u8]), vec![254u8]);
388 assert_eq!(strinc(vec![253u8, 255u8, 255u8]), vec![254u8]);
389 assert_eq!(strinc(vec![255u8, 255u8, 255u8]), Vec::<u8>::new());
390 }
391}