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