Skip to main content

rustic_core/repository/
status.rs

1use bytes::Bytes;
2
3use crate::{
4    BlobId, RusticResult,
5    backend::{cache::Cache, decrypt::DecryptBackend},
6    crypto::aespoly1305::Key,
7    index::GlobalIndex,
8    repofile::{ConfigFile, KeyId},
9};
10
11/// A repository which is open, i.e. the password has been checked and the decryption key is available.
12pub trait Open {
13    /// Get the open status
14    fn open_status(&self) -> &OpenStatus;
15    /// Get the mutable open status
16    fn open_status_mut(&mut self) -> &mut OpenStatus;
17    /// Get the open status
18    fn into_open_status(self) -> OpenStatus;
19}
20
21/// A repository which is indexed such that all tree blobs are contained in the index.
22pub trait IndexedTree: Open {
23    /// Returns the used indexes
24    fn index(&self) -> &GlobalIndex;
25}
26
27/// A repository which is indexed such that all tree blobs are contained in the index
28/// and additionally the `Id`s of data blobs are also contained in the index.
29pub trait IndexedIds: IndexedTree {
30    /// Turn the repository into the `IndexedTree` state by reading and storing a size-optimized index
31    fn into_indexed_tree(self) -> IndexedTreesStatus;
32}
33
34/// A repository which is indexed such that all blob information is fully contained in the index.
35pub trait IndexedFull: IndexedIds {
36    /// Get a blob from the internal cache blob or insert it with the given function
37    ///
38    /// # Arguments
39    ///
40    /// * `id` - The [`Id`] of the blob to get
41    /// * `with` - The function which fetches the blob from the repository if it is not contained in the cache
42    ///
43    /// # Errors
44    ///
45    /// * If the blob could not be fetched from the repository.
46    ///
47    /// # Returns
48    ///
49    /// The blob with the given id or the result of the given function if the blob is not contained in the cache
50    /// and the function is called.
51    fn get_blob_or_insert_with(
52        &self,
53        id: &BlobId,
54        with: impl FnOnce() -> RusticResult<Bytes>,
55    ) -> RusticResult<Bytes>;
56}
57
58/// Open Status: This repository is open, i.e. the password has been checked and the decryption key is available.
59#[derive(Debug)]
60pub struct OpenStatus {
61    /// The cache
62    pub(super) cache: Option<Cache>,
63    /// The [`DecryptBackend`]
64    pub(super) dbe: DecryptBackend<Key>,
65    /// The [`ConfigFile`]
66    pub(super) config: ConfigFile,
67    /// The [`KeyId`] of the used key
68    pub(super) key_id: Option<KeyId>,
69}
70
71impl Open for OpenStatus {
72    fn open_status(&self) -> &OpenStatus {
73        self
74    }
75    fn open_status_mut(&mut self) -> &mut OpenStatus {
76        self
77    }
78    fn into_open_status(self) -> OpenStatus {
79        self
80    }
81}
82
83/// Indexed Tree Status: The repository is open and the index contains trees.
84#[derive(Debug)]
85pub struct IndexedTreesStatus {
86    /// The open status
87    pub(super) open: OpenStatus,
88    /// The index backend
89    pub(super) index: GlobalIndex,
90}
91
92impl Open for IndexedTreesStatus {
93    fn open_status(&self) -> &OpenStatus {
94        &self.open
95    }
96    fn open_status_mut(&mut self) -> &mut OpenStatus {
97        &mut self.open
98    }
99    fn into_open_status(self) -> OpenStatus {
100        self.open
101    }
102}
103
104impl IndexedTree for IndexedTreesStatus {
105    fn index(&self) -> &GlobalIndex {
106        &self.index
107    }
108}
109
110/// Indexed Tree Status: The repository is open and the index contains tree packs and the ids for data packs.
111#[derive(Debug)]
112pub struct IndexedIdsStatus {
113    /// The open status
114    pub(super) open: OpenStatus,
115    /// The index backend
116    pub(super) index: GlobalIndex,
117}
118
119impl Open for IndexedIdsStatus {
120    fn open_status(&self) -> &OpenStatus {
121        &self.open
122    }
123    fn open_status_mut(&mut self) -> &mut OpenStatus {
124        &mut self.open
125    }
126    fn into_open_status(self) -> OpenStatus {
127        self.open
128    }
129}
130
131impl IndexedTree for IndexedIdsStatus {
132    fn index(&self) -> &GlobalIndex {
133        &self.index
134    }
135}
136
137impl IndexedIds for IndexedIdsStatus {
138    fn into_indexed_tree(self) -> IndexedTreesStatus {
139        IndexedTreesStatus {
140            open: self.open,
141            index: self.index.drop_data(),
142        }
143    }
144}
145
146#[derive(Clone, Copy, Debug)]
147/// Defines a weighted cache with weight equal to the length of the blob size
148pub(crate) struct BytesWeighter;
149
150impl quick_cache::Weighter<BlobId, Bytes> for BytesWeighter {
151    fn weight(&self, _key: &BlobId, val: &Bytes) -> u64 {
152        u64::try_from(val.len())
153            .expect("weight overflow in cache should not happen")
154            // Be cautions out about zero weights!
155            .max(1)
156    }
157}
158/// Indexed Tree Status: The repository is open and the index contains trees.
159///
160#[derive(Debug)]
161pub struct IndexedFullStatus {
162    /// The open status
163    pub(super) open: OpenStatus,
164    /// The index backend
165    pub(super) index: GlobalIndex,
166    pub(super) cache: quick_cache::sync::Cache<BlobId, Bytes, BytesWeighter>,
167}
168
169impl Open for IndexedFullStatus {
170    fn open_status(&self) -> &OpenStatus {
171        &self.open
172    }
173    fn open_status_mut(&mut self) -> &mut OpenStatus {
174        &mut self.open
175    }
176    fn into_open_status(self) -> OpenStatus {
177        self.open
178    }
179}
180
181impl IndexedTree for IndexedFullStatus {
182    fn index(&self) -> &GlobalIndex {
183        &self.index
184    }
185}
186
187impl IndexedIds for IndexedFullStatus {
188    fn into_indexed_tree(self) -> IndexedTreesStatus {
189        IndexedTreesStatus {
190            open: self.open,
191            index: self.index.drop_data(),
192        }
193    }
194}
195
196impl IndexedFull for IndexedFullStatus {
197    fn get_blob_or_insert_with(
198        &self,
199        id: &BlobId,
200        with: impl FnOnce() -> RusticResult<Bytes>,
201    ) -> RusticResult<Bytes> {
202        self.cache.get_or_insert_with(id, with)
203    }
204}