lockbook_shared/
staged.rs

1use crate::file_like::FileLike;
2use crate::tree_like::{TreeLike, TreeLikeMut};
3use crate::SharedResult;
4use std::collections::HashSet;
5use uuid::Uuid;
6
7pub trait StagedTreeLike: TreeLike {
8    type Base: TreeLike<F = Self::F>;
9    type Staged: TreeLike<F = Self::F>;
10
11    fn base(&self) -> &Self::Base;
12    fn staged(&self) -> &Self::Staged;
13}
14
15// todo: make this trait not generic once associated type bounds are stabilized
16// https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html
17pub trait StagedTreeLikeMut<Base, Staged>:
18    StagedTreeLike<Base = Base, Staged = Staged> + TreeLikeMut
19where
20    Base: TreeLike<F = Self::F>,
21    Staged: TreeLikeMut<F = Self::F>,
22{
23    fn staged_mut(&mut self) -> &mut Self::Staged;
24
25    fn prune(&mut self) -> SharedResult<()> {
26        let mut prunable = vec![];
27        for id in self.staged().ids() {
28            if let Some(staged) = self.staged().maybe_find(id) {
29                if let Some(base) = self.base().maybe_find(id) {
30                    if staged == base {
31                        prunable.push(*id);
32                    }
33                }
34            }
35        }
36
37        for id in prunable {
38            self.staged_mut().remove(id)?;
39        }
40        Ok(())
41    }
42
43    fn pruned(mut self) -> SharedResult<Self> {
44        self.prune()?;
45        Ok(self)
46    }
47}
48
49#[derive(Debug)]
50pub struct StagedTree<Base, Staged>
51where
52    Base: TreeLike,
53    Staged: TreeLike<F = Base::F>,
54{
55    pub base: Base,
56    pub staged: Staged,
57    pub removed: HashSet<Uuid>,
58}
59
60impl<Base, Staged> StagedTree<Base, Staged>
61where
62    Base: TreeLike,
63    Staged: TreeLike<F = Base::F>,
64{
65    pub fn new(base: Base, staged: Staged) -> Self {
66        Self { base, staged, removed: HashSet::new() }
67    }
68}
69
70impl<Base> StagedTree<Base, Option<Base::F>>
71where
72    Base: TreeLike,
73{
74    pub fn removal(base: Base, removed: HashSet<Uuid>) -> Self {
75        Self { base, staged: None, removed }
76    }
77}
78
79impl<Base, Staged> TreeLike for StagedTree<Base, Staged>
80where
81    Base: TreeLike,
82    Staged: TreeLike<F = Base::F>,
83{
84    type F = Base::F;
85
86    fn ids(&self) -> HashSet<&Uuid> {
87        self.base()
88            .ids()
89            .into_iter()
90            .chain(self.staged().ids())
91            .filter(|id| !self.removed.contains(id))
92            .collect()
93    }
94
95    fn maybe_find(&self, id: &Uuid) -> Option<&Self::F> {
96        if self.removed.contains(id) {
97            None
98        } else {
99            self.staged()
100                .maybe_find(id)
101                .or_else(|| self.base().maybe_find(id))
102        }
103    }
104}
105
106impl<Base, Staged> TreeLikeMut for StagedTree<Base, Staged>
107where
108    Base: TreeLike,
109    Staged: TreeLikeMut<F = Base::F>,
110{
111    fn insert(&mut self, f: Self::F) -> SharedResult<Option<Self::F>> {
112        self.removed.remove(f.id());
113        if let Some(base) = self.base.maybe_find(f.id()) {
114            if *base == f {
115                return self.staged.remove(*f.id());
116            }
117        }
118
119        self.staged.insert(f)
120    }
121
122    fn remove(&mut self, id: Uuid) -> SharedResult<Option<Self::F>> {
123        self.removed.insert(id);
124        if let Some(staged) = self.staged.remove(id)? {
125            Ok(Some(staged))
126        } else {
127            Ok(self.base.maybe_find(&id).cloned())
128        }
129    }
130
131    fn clear(&mut self) -> SharedResult<()> {
132        self.removed.extend(self.owned_ids());
133        Ok(())
134    }
135}
136
137impl<Base, Staged> StagedTreeLike for StagedTree<Base, Staged>
138where
139    Base: TreeLike,
140    Staged: TreeLike<F = Base::F>,
141{
142    type Base = Base;
143    type Staged = Staged;
144
145    fn base(&self) -> &Self::Base {
146        &self.base
147    }
148
149    fn staged(&self) -> &Self::Staged {
150        &self.staged
151    }
152}
153
154impl<Base, Staged> StagedTreeLikeMut<Base, Staged> for StagedTree<Base, Staged>
155where
156    Base: TreeLike,
157    Staged: TreeLikeMut<F = Base::F>,
158{
159    fn staged_mut(&mut self) -> &mut Self::Staged {
160        &mut self.staged
161    }
162}