1use crate::{BlobFormat, Hash, HashAndFormat};
3
4#[cfg(feature = "fs-store")]
5mod bao_file;
6pub mod mem;
7mod mutable_mem_storage;
8pub mod readonly_mem;
9
10#[cfg(feature = "fs-store")]
11pub mod fs;
12
13mod traits;
14use tracing::warn;
15pub use traits::*;
16
17fn new_uuid() -> [u8; 16] {
19 use rand::Rng;
20 rand::thread_rng().gen::<[u8; 16]>()
21}
22
23fn temp_name() -> String {
25 format!("{}.temp", hex::encode(new_uuid()))
26}
27
28#[derive(Debug, Default, Clone)]
29struct TempCounters {
30 raw: u64,
32 hash_seq: u64,
34}
35
36impl TempCounters {
37 fn counter(&mut self, format: BlobFormat) -> &mut u64 {
38 match format {
39 BlobFormat::Raw => &mut self.raw,
40 BlobFormat::HashSeq => &mut self.hash_seq,
41 }
42 }
43
44 fn inc(&mut self, format: BlobFormat) {
45 let counter = self.counter(format);
46 *counter = counter.checked_add(1).unwrap();
47 }
48
49 fn dec(&mut self, format: BlobFormat) {
50 let counter = self.counter(format);
51 *counter = counter.saturating_sub(1);
52 }
53
54 fn is_empty(&self) -> bool {
55 self.raw == 0 && self.hash_seq == 0
56 }
57}
58
59#[derive(Debug, Clone, Default)]
60struct TempCounterMap(std::collections::BTreeMap<Hash, TempCounters>);
61
62impl TempCounterMap {
63 fn inc(&mut self, value: &HashAndFormat) {
64 let HashAndFormat { hash, format } = value;
65 self.0.entry(*hash).or_default().inc(*format)
66 }
67
68 fn dec(&mut self, value: &HashAndFormat) {
69 let HashAndFormat { hash, format } = value;
70 let Some(counters) = self.0.get_mut(hash) else {
71 warn!("Decrementing non-existent temp tag");
72 return;
73 };
74 counters.dec(*format);
75 if counters.is_empty() {
76 self.0.remove(hash);
77 }
78 }
79
80 fn contains(&self, hash: &Hash) -> bool {
81 self.0.contains_key(hash)
82 }
83
84 fn keys(&self) -> impl Iterator<Item = HashAndFormat> {
85 let mut res = Vec::new();
86 for (k, v) in self.0.iter() {
87 if v.raw > 0 {
88 res.push(HashAndFormat::raw(*k));
89 }
90 if v.hash_seq > 0 {
91 res.push(HashAndFormat::hash_seq(*k));
92 }
93 }
94 res.into_iter()
95 }
96}