lb_rs/model/
staged.rs

1use crate::model::file_like::FileLike;
2use crate::model::tree_like::{TreeLike, TreeLikeMut};
3use std::collections::HashSet;
4use uuid::Uuid;
5
6use super::errors::LbResult;
7
8pub trait StagedTreeLike: TreeLike {
9    type Base: TreeLike<F = Self::F>;
10    type Staged: TreeLike<F = Self::F>;
11
12    fn base(&self) -> &Self::Base;
13    fn staged(&self) -> &Self::Staged;
14}
15
16// todo: make this trait not generic once associated type bounds are stabilized
17// https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html
18pub trait StagedTreeLikeMut<Base, Staged>:
19    StagedTreeLike<Base = Base, Staged = Staged> + TreeLikeMut
20where
21    Base: TreeLike<F = Self::F>,
22    Staged: TreeLikeMut<F = Self::F>,
23{
24    fn staged_mut(&mut self) -> &mut Self::Staged;
25
26    fn prune(&mut self) -> LbResult<()> {
27        let mut prunable = vec![];
28        for id in self.staged().ids() {
29            if let Some(staged) = self.staged().maybe_find(&id) {
30                if let Some(base) = self.base().maybe_find(&id) {
31                    if staged == base {
32                        prunable.push(id);
33                    }
34                }
35            }
36        }
37
38        for id in prunable {
39            self.staged_mut().remove(id)?;
40        }
41        Ok(())
42    }
43
44    fn pruned(mut self) -> LbResult<Self> {
45        self.prune()?;
46        Ok(self)
47    }
48}
49
50#[derive(Clone, Debug)]
51pub struct StagedTree<Base, Staged>
52where
53    Base: TreeLike,
54    Staged: TreeLike<F = Base::F>,
55{
56    pub base: Base,
57    pub staged: Staged,
58    pub new: HashSet<Uuid>,
59    pub removed: HashSet<Uuid>,
60}
61
62impl<Base, Staged> StagedTree<Base, Staged>
63where
64    Base: TreeLike,
65    Staged: TreeLike<F = Base::F>,
66{
67    pub fn new(base: Base, staged: Staged) -> Self {
68        let mut new = HashSet::new();
69        for id in staged.ids() {
70            if base.maybe_find(&id).is_none() {
71                new.insert(id);
72            }
73        }
74        Self { base, staged, removed: HashSet::new(), new }
75    }
76}
77
78impl<Base> StagedTree<Base, Option<Base::F>>
79where
80    Base: TreeLike,
81{
82    // todo: this is dead code
83    pub fn removal(base: Base, removed: HashSet<Uuid>) -> Self {
84        Self { base, staged: None, removed, new: Default::default() }
85    }
86}
87
88impl<T> StagedTreeLike for &T
89where
90    T: StagedTreeLike,
91{
92    type Base = T::Base;
93    type Staged = T::Staged;
94
95    fn base(&self) -> &Self::Base {
96        T::base(self)
97    }
98    fn staged(&self) -> &Self::Staged {
99        T::staged(self)
100    }
101}
102
103impl<T> StagedTreeLike for &mut T
104where
105    T: StagedTreeLike,
106{
107    type Base = T::Base;
108    type Staged = T::Staged;
109
110    fn base(&self) -> &Self::Base {
111        T::base(self)
112    }
113    fn staged(&self) -> &Self::Staged {
114        T::staged(self)
115    }
116}
117
118impl<Base, Staged, T> StagedTreeLikeMut<Base, Staged> for &mut T
119where
120    Base: TreeLike<F = T::F>,
121    Staged: TreeLikeMut<F = T::F>,
122    T: StagedTreeLikeMut<Base, Staged>,
123{
124    fn staged_mut(&mut self) -> &mut Self::Staged {
125        T::staged_mut(self)
126    }
127}
128
129impl<Base, Staged> TreeLike for StagedTree<Base, Staged>
130where
131    Base: TreeLike,
132    Staged: TreeLike<F = Base::F>,
133{
134    type F = Base::F;
135
136    fn ids(&self) -> Vec<Uuid> {
137        let mut all_ids = self.base.ids();
138        all_ids.extend(&self.new);
139        all_ids.retain(|id| !self.removed.contains(id));
140
141        all_ids
142    }
143
144    fn maybe_find(&self, id: &Uuid) -> Option<&Self::F> {
145        if self.removed.contains(id) {
146            None
147        } else {
148            self.staged()
149                .maybe_find(id)
150                .or_else(|| self.base().maybe_find(id))
151        }
152    }
153}
154
155impl<Base, Staged> TreeLikeMut for StagedTree<Base, Staged>
156where
157    Base: TreeLike,
158    Staged: TreeLikeMut<F = Base::F>,
159{
160    fn insert(&mut self, f: Self::F) -> LbResult<Option<Self::F>> {
161        // if we're inserting it, it can't be removed
162        self.removed.remove(f.id());
163
164        if let Some(base) = self.base.maybe_find(f.id()) {
165            if *base == f {
166                return self.staged.remove(*f.id());
167            }
168        } else {
169            self.new.insert(*f.id());
170        }
171
172        self.staged.insert(f)
173    }
174
175    fn remove(&mut self, id: Uuid) -> LbResult<Option<Self::F>> {
176        self.removed.insert(id);
177        if let Some(staged) = self.staged.remove(id)? {
178            Ok(Some(staged))
179        } else {
180            Ok(self.base.maybe_find(&id).cloned())
181        }
182    }
183
184    fn clear(&mut self) -> LbResult<()> {
185        self.removed.extend(self.ids());
186        Ok(())
187    }
188}
189
190impl<Base, Staged> StagedTreeLike for StagedTree<Base, Staged>
191where
192    Base: TreeLike,
193    Staged: TreeLike<F = Base::F>,
194{
195    type Base = Base;
196    type Staged = Staged;
197
198    fn base(&self) -> &Self::Base {
199        &self.base
200    }
201
202    fn staged(&self) -> &Self::Staged {
203        &self.staged
204    }
205}
206
207impl<Base, Staged> StagedTreeLikeMut<Base, Staged> for StagedTree<Base, Staged>
208where
209    Base: TreeLike,
210    Staged: TreeLikeMut<F = Base::F>,
211{
212    fn staged_mut(&mut self) -> &mut Self::Staged {
213        &mut self.staged
214    }
215}