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#[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 pub(crate) async fn fork(&self, dst_branch: &Branch) -> Result<()> {
153 if self.branch().id() == dst_branch.id() {
154 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<'_> {}