ouisync/directory/
entry.rs

1use super::{
2    content::Content,
3    entry_data::{EntryData, EntryDirectoryData, EntryFileData, EntryTombstoneData},
4    parent_context::ParentContext,
5    Directory, DirectoryFallback, DirectoryLocking,
6};
7use crate::{
8    blob::BlobId,
9    branch::Branch,
10    crypto::sign::PublicKey,
11    error::{Error, Result},
12    file::File,
13    protocol::Locator,
14    store::ReadTransaction,
15    version_vector::VersionVector,
16    versioned::{BranchItem, Versioned},
17};
18use std::fmt;
19
20/// Info about a directory entry.
21#[derive(Copy, Clone, Debug)]
22pub enum EntryRef<'a> {
23    File(FileRef<'a>),
24    Directory(DirectoryRef<'a>),
25    Tombstone(TombstoneRef<'a>),
26}
27
28impl<'a> EntryRef<'a> {
29    pub(super) fn new(parent: &'a Directory, name: &'a str, entry_data: &'a EntryData) -> Self {
30        let inner = RefInner { parent, name };
31
32        match entry_data {
33            EntryData::File(entry_data) => Self::File(FileRef { entry_data, inner }),
34            EntryData::Directory(entry_data) => Self::Directory(DirectoryRef { entry_data, inner }),
35            EntryData::Tombstone(entry_data) => Self::Tombstone(TombstoneRef { entry_data, inner }),
36        }
37    }
38
39    pub fn name(&self) -> &'a str {
40        match self {
41            Self::File(r) => r.name(),
42            Self::Directory(r) => r.name(),
43            Self::Tombstone(r) => r.name(),
44        }
45    }
46
47    pub fn version_vector(&self) -> &'a VersionVector {
48        match self {
49            Self::File(f) => f.version_vector(),
50            Self::Directory(d) => d.version_vector(),
51            Self::Tombstone(t) => t.version_vector(),
52        }
53    }
54
55    pub fn file(self) -> Result<FileRef<'a>> {
56        match self {
57            Self::File(r) => Ok(r),
58            Self::Directory(_) => Err(Error::EntryIsDirectory),
59            Self::Tombstone(_) => Err(Error::EntryNotFound),
60        }
61    }
62
63    pub fn directory(self) -> Result<DirectoryRef<'a>> {
64        match self {
65            Self::File(_) => Err(Error::EntryIsFile),
66            Self::Directory(r) => Ok(r),
67            Self::Tombstone(_) => Err(Error::EntryNotFound),
68        }
69    }
70
71    pub fn is_file(&self) -> bool {
72        matches!(self, Self::File(_))
73    }
74
75    pub fn is_directory(&self) -> bool {
76        matches!(self, Self::Directory(_))
77    }
78
79    pub fn is_tombstone(&self) -> bool {
80        matches!(self, Self::Tombstone(_))
81    }
82
83    pub fn branch_id(&self) -> &PublicKey {
84        self.inner().branch_id()
85    }
86
87    pub fn parent(&self) -> &Directory {
88        self.inner().parent
89    }
90
91    pub(crate) fn clone_data(&self) -> EntryData {
92        match self {
93            Self::File(e) => EntryData::File(e.data().clone()),
94            Self::Directory(e) => EntryData::Directory(e.data().clone()),
95            Self::Tombstone(e) => EntryData::Tombstone(e.data().clone()),
96        }
97    }
98
99    fn inner(&self) -> &RefInner {
100        match self {
101            Self::File(r) => &r.inner,
102            Self::Directory(r) => &r.inner,
103            Self::Tombstone(r) => &r.inner,
104        }
105    }
106}
107
108impl Versioned for EntryRef<'_> {
109    fn version_vector(&self) -> &VersionVector {
110        EntryRef::version_vector(self)
111    }
112}
113
114impl BranchItem for EntryRef<'_> {
115    fn branch_id(&self) -> &PublicKey {
116        EntryRef::branch_id(self)
117    }
118}
119
120#[derive(Copy, Clone)]
121pub struct FileRef<'a> {
122    entry_data: &'a EntryFileData,
123    inner: RefInner<'a>,
124}
125
126impl<'a> FileRef<'a> {
127    pub fn name(&self) -> &'a str {
128        self.inner.name
129    }
130
131    pub(crate) fn locator(&self) -> Locator {
132        Locator::head(*self.blob_id())
133    }
134
135    pub(crate) fn blob_id(&self) -> &'a BlobId {
136        &self.entry_data.blob_id
137    }
138
139    pub fn version_vector(&self) -> &'a VersionVector {
140        &self.entry_data.version_vector
141    }
142
143    pub async fn open(&self) -> Result<File> {
144        let parent_context = self.inner.parent_context();
145        let branch = self.branch().clone();
146        let locator = self.locator();
147
148        File::open(branch, locator, parent_context).await
149    }
150
151    /// Fork the file without opening it.
152    pub(crate) async fn fork(&self, dst_branch: &Branch) -> Result<()> {
153        if self.branch().id() == dst_branch.id() {
154            // Already forked
155            return Ok(());
156        }
157
158        let parent_context = self.inner.parent_context();
159        let src_branch = self.branch();
160
161        parent_context.fork(src_branch, dst_branch).await?;
162
163        Ok(())
164    }
165
166    pub fn branch(&self) -> &Branch {
167        self.inner.branch()
168    }
169
170    pub fn parent(&self) -> &Directory {
171        self.inner.parent
172    }
173
174    pub(crate) fn data(&self) -> &EntryFileData {
175        self.entry_data
176    }
177}
178
179impl fmt::Debug for FileRef<'_> {
180    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181        f.debug_struct("FileRef")
182            .field("name", &self.inner.name)
183            .field("vv", &self.entry_data.version_vector)
184            .field("locator", &self.locator())
185            .finish()
186    }
187}
188
189#[derive(Copy, Clone)]
190pub struct DirectoryRef<'a> {
191    entry_data: &'a EntryDirectoryData,
192    inner: RefInner<'a>,
193}
194
195impl<'a> DirectoryRef<'a> {
196    pub fn name(&self) -> &'a str {
197        self.inner.name
198    }
199
200    pub(crate) fn locator(&self) -> Locator {
201        Locator::head(*self.blob_id())
202    }
203
204    pub(crate) fn blob_id(&self) -> &'a BlobId {
205        &self.entry_data.blob_id
206    }
207
208    pub(crate) async fn open(&self, fallback: DirectoryFallback) -> Result<Directory> {
209        Directory::open(
210            self.branch().clone(),
211            *self.blob_id(),
212            Some(self.inner.parent_context()),
213            if self.inner.parent.lock.is_some() {
214                DirectoryLocking::Enabled
215            } else {
216                DirectoryLocking::Disabled
217            },
218            fallback,
219        )
220        .await
221    }
222
223    pub(super) async fn open_snapshot(
224        &self,
225        tx: &mut ReadTransaction,
226        fallback: DirectoryFallback,
227    ) -> Result<Content> {
228        Directory::open_snapshot(tx, self.branch().clone(), self.locator(), fallback).await
229    }
230
231    pub fn branch(&self) -> &'a Branch {
232        self.inner.branch()
233    }
234
235    pub(crate) fn data(&self) -> &EntryDirectoryData {
236        self.entry_data
237    }
238
239    pub fn version_vector(&self) -> &'a VersionVector {
240        &self.entry_data.version_vector
241    }
242}
243
244impl fmt::Debug for DirectoryRef<'_> {
245    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246        f.debug_struct("DirectoryRef")
247            .field("name", &self.inner.name)
248            .finish()
249    }
250}
251
252#[derive(Copy, Clone)]
253pub struct TombstoneRef<'a> {
254    entry_data: &'a EntryTombstoneData,
255    inner: RefInner<'a>,
256}
257
258impl<'a> TombstoneRef<'a> {
259    pub fn name(&self) -> &'a str {
260        self.inner.name
261    }
262
263    pub fn branch_id(&self) -> &'a PublicKey {
264        self.inner.branch_id()
265    }
266
267    pub(crate) fn data(&self) -> &EntryTombstoneData {
268        self.entry_data
269    }
270
271    pub fn version_vector(&self) -> &'a VersionVector {
272        &self.entry_data.version_vector
273    }
274}
275
276impl fmt::Debug for TombstoneRef<'_> {
277    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278        f.debug_struct("TombstoneRef")
279            .field("vv", &self.entry_data.version_vector)
280            .finish()
281    }
282}
283
284#[derive(Copy, Clone)]
285struct RefInner<'a> {
286    parent: &'a Directory,
287    name: &'a str,
288}
289
290impl<'a> RefInner<'a> {
291    fn parent_context(&self) -> ParentContext {
292        self.parent.create_parent_context(self.name.into())
293    }
294
295    fn branch(&self) -> &'a Branch {
296        self.parent.blob.branch()
297    }
298
299    pub fn branch_id(&self) -> &'a PublicKey {
300        self.parent.blob.branch().id()
301    }
302}
303
304impl PartialEq for RefInner<'_> {
305    fn eq(&self, other: &Self) -> bool {
306        self.parent.blob.branch().id() == other.parent.blob.branch().id()
307            && self.parent.blob.id() == other.parent.blob.id()
308            && self.name == other.name
309    }
310}
311
312impl Eq for RefInner<'_> {}