grovedb_path/
subtree_path_builder.rs

1// MIT LICENSE
2//
3// Copyright (c) 2023 Dash Core Group
4//
5// Permission is hereby granted, free of charge, to any
6// person obtaining a copy of this software and associated
7// documentation files (the "Software"), to deal in the
8// Software without restriction, including without
9// limitation the rights to use, copy, modify, merge,
10// publish, distribute, sublicense, and/or sell copies of
11// the Software, and to permit persons to whom the Software
12// is furnished to do so, subject to the following
13// conditions:
14//
15// The above copyright notice and this permission notice
16// shall be included in all copies or substantial portions
17// of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
20// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
21// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
22// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
23// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
26// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27// DEALINGS IN THE SOFTWARE.
28
29//! Difinitions of versatile type representing a path to a subtree that can own
30//! certain path segments.
31
32use std::hash::{Hash, Hasher};
33
34use crate::{
35    subtree_path::SubtreePathInner,
36    util::{CompactBytes, CowLike},
37    SubtreePath, SubtreePathIter,
38};
39
40/// Path to a GroveDB's subtree.
41#[derive(Debug)]
42pub struct SubtreePathBuilder<'b, B> {
43    /// Derivation starting point.
44    pub(crate) base: SubtreePath<'b, B>,
45    /// Path information relative to [base](Self::base).
46    pub(crate) relative: SubtreePathRelative<'b>,
47}
48
49/// Hash order is the same as iteration order: from most deep path segment up to
50/// root.
51impl<'b, B: AsRef<[u8]>> Hash for SubtreePathBuilder<'b, B> {
52    fn hash<H: Hasher>(&self, state: &mut H) {
53        self.relative.hash(state);
54        self.base.hash(state);
55    }
56}
57
58impl<'bl, 'br, BL, BR> PartialEq<SubtreePathBuilder<'br, BR>> for SubtreePathBuilder<'bl, BL>
59where
60    BL: AsRef<[u8]>,
61    BR: AsRef<[u8]>,
62{
63    fn eq(&self, other: &SubtreePathBuilder<'br, BR>) -> bool {
64        self.reverse_iter().eq(other.reverse_iter())
65    }
66}
67
68impl<'bl, 'br, BL, BR> PartialEq<SubtreePathBuilder<'br, BR>> for SubtreePath<'bl, BL>
69where
70    BL: AsRef<[u8]>,
71    BR: AsRef<[u8]>,
72{
73    fn eq(&self, other: &SubtreePathBuilder<'br, BR>) -> bool {
74        self.clone().into_reverse_iter().eq(other.reverse_iter())
75    }
76}
77
78impl<'bl, 'br, BL, BR> PartialEq<SubtreePath<'br, BR>> for SubtreePathBuilder<'bl, BL>
79where
80    BL: AsRef<[u8]>,
81    BR: AsRef<[u8]>,
82{
83    fn eq(&self, other: &SubtreePath<'br, BR>) -> bool {
84        self.reverse_iter().eq(other.clone().into_reverse_iter())
85    }
86}
87
88impl<'b, B: AsRef<[u8]>> Eq for SubtreePathBuilder<'b, B> {}
89
90impl<'s, 'b, B> From<&'s SubtreePath<'b, B>> for SubtreePathBuilder<'b, B> {
91    fn from(value: &'s SubtreePath<'b, B>) -> Self {
92        SubtreePathBuilder {
93            base: value.clone(),
94            relative: SubtreePathRelative::Empty,
95        }
96    }
97}
98
99/// Derived subtree path on top of base path.
100#[derive(Debug)]
101pub(crate) enum SubtreePathRelative<'r> {
102    /// Equivalent to the base path.
103    Empty,
104    /// Added one child segment.
105    Single(CowLike<'r>),
106    /// Derivation with multiple owned path segments at once
107    Multi(CompactBytes),
108}
109
110impl SubtreePathRelative<'_> {
111    pub fn len(&self) -> usize {
112        match self {
113            SubtreePathRelative::Empty => 0,
114            SubtreePathRelative::Single(_) => 1,
115            SubtreePathRelative::Multi(cb) => cb.len(),
116        }
117    }
118
119    pub fn is_empty(&self) -> bool {
120        matches!(self, SubtreePathRelative::Empty)
121    }
122}
123
124impl Hash for SubtreePathRelative<'_> {
125    fn hash<H: Hasher>(&self, state: &mut H) {
126        match self {
127            SubtreePathRelative::Empty => {}
128            SubtreePathRelative::Single(segment) => segment.hash(state),
129            SubtreePathRelative::Multi(bytes) => {
130                bytes.reverse_iter().for_each(|segment| segment.hash(state))
131            }
132        }
133    }
134}
135
136impl SubtreePathBuilder<'static, [u8; 0]> {
137    /// Creates empty subtree path
138    pub fn new() -> Self {
139        SubtreePathBuilder {
140            base: [].as_ref().into(),
141            relative: SubtreePathRelative::Empty,
142        }
143    }
144}
145
146impl Default for SubtreePathBuilder<'static, [u8; 0]> {
147    fn default() -> Self {
148        Self::new()
149    }
150}
151
152impl<B> SubtreePathBuilder<'_, B> {
153    /// Returns the length of the subtree path.
154    pub fn len(&self) -> usize {
155        self.base.len() + self.relative.len()
156    }
157
158    /// Returns whether the path is empty (the root tree).
159    pub fn is_empty(&self) -> bool {
160        self.base.is_empty() && self.relative.is_empty()
161    }
162}
163
164impl<'b, B: AsRef<[u8]>> SubtreePathBuilder<'b, B> {
165    /// Get a derived path that will use another subtree path (or reuse the base
166    /// slice) as it's base, then could be edited in place.
167    pub fn derive_owned(&'b self) -> SubtreePathBuilder<'b, B> {
168        match self.relative {
169            // If this derived path makes no difference, derive from base
170            SubtreePathRelative::Empty => self.base.derive_owned(),
171            // Otherwise a new derived subtree path must point to this one as it's base
172            _ => SubtreePathBuilder {
173                base: SubtreePathInner::SubtreePath(self).into(),
174                relative: SubtreePathRelative::Empty,
175            },
176        }
177    }
178
179    /// Get a derived path for a parent and a chopped segment. Returned
180    /// [SubtreePath] will be linked to this [SubtreePath] because it might
181    /// contain owned data and it has to outlive [SubtreePath].
182    pub fn derive_parent(&self) -> Option<(SubtreePath<B>, &[u8])> {
183        match &self.relative {
184            SubtreePathRelative::Empty => self.base.derive_parent(),
185            SubtreePathRelative::Single(relative) => Some((self.base.clone(), relative.as_ref())),
186            SubtreePathRelative::Multi(_) => {
187                let mut iter = self.reverse_iter();
188                iter.next()
189                    .map(|segment| (SubtreePathInner::SubtreePathIter(iter).into(), segment))
190            }
191        }
192    }
193
194    /// Get a derived path with a child path segment added.
195    pub fn derive_owned_with_child<'s, S>(&'b self, segment: S) -> SubtreePathBuilder<'b, B>
196    where
197        S: Into<CowLike<'s>>,
198        's: 'b,
199    {
200        SubtreePathBuilder {
201            base: SubtreePathInner::SubtreePath(self).into(),
202            relative: SubtreePathRelative::Single(segment.into()),
203        }
204    }
205
206    /// Adds path segment in place.
207    pub fn push_segment(&mut self, segment: &[u8]) {
208        match &mut self.relative {
209            SubtreePathRelative::Empty => {
210                let mut bytes = CompactBytes::new();
211                bytes.add_segment(segment);
212                self.relative = SubtreePathRelative::Multi(bytes);
213            }
214            SubtreePathRelative::Single(old_segment) => {
215                let mut bytes = CompactBytes::new();
216                bytes.add_segment(old_segment);
217                bytes.add_segment(segment);
218                self.relative = SubtreePathRelative::Multi(bytes);
219            }
220            SubtreePathRelative::Multi(bytes) => bytes.add_segment(segment),
221        }
222    }
223
224    /// Returns an iterator for the subtree path by path segments.
225    pub fn reverse_iter(&'b self) -> SubtreePathIter<'b, B> {
226        match &self.relative {
227            SubtreePathRelative::Empty => self.base.clone().into_reverse_iter(),
228            SubtreePathRelative::Single(item) => {
229                SubtreePathIter::new_with_next(item.as_ref(), &self.base)
230            }
231            SubtreePathRelative::Multi(bytes) => {
232                SubtreePathIter::new_with_next(bytes.reverse_iter(), &self.base)
233            }
234        }
235    }
236
237    /// Collect path as a vector of vectors, but this actually negates all the
238    /// benefits of this library.
239    pub fn to_vec(&self) -> Vec<Vec<u8>> {
240        let mut result = Vec::new();
241
242        // Because of the nature of this library, the vector will be built
243        // from it's end
244        match &self.relative {
245            SubtreePathRelative::Empty => {}
246            SubtreePathRelative::Single(s) => result.push(s.to_vec()),
247            SubtreePathRelative::Multi(bytes) => {
248                bytes.reverse_iter().for_each(|s| result.push(s.to_vec()))
249            }
250        }
251
252        match &self.base.ref_variant {
253            SubtreePathInner::Slice(slice) => slice
254                .iter()
255                .rev()
256                .for_each(|x| result.push(x.as_ref().to_vec())),
257            SubtreePathInner::SubtreePath(path) => {
258                path.reverse_iter().for_each(|x| result.push(x.to_vec()))
259            }
260            SubtreePathInner::SubtreePathIter(iter) => {
261                iter.clone().for_each(|x| result.push(x.as_ref().to_vec()))
262            }
263        };
264
265        result.reverse();
266        result
267    }
268
269    /// Retuns `true` if the subtree path is empty, so it points to the root
270    /// tree.
271    pub fn is_root(&self) -> bool {
272        match self {
273            Self {
274                base,
275                relative: SubtreePathRelative::Empty,
276            } => base.is_root(),
277            _ => false,
278        }
279    }
280}
281
282#[cfg(test)]
283mod tests {
284    use super::*;
285
286    #[test]
287    fn to_vec() {
288        let base: SubtreePath<_> = (&[b"one" as &[u8], b"two", b"three"]).into();
289        let mut builder = base.derive_owned_with_child(b"four");
290        builder.push_segment(b"five");
291        builder.push_segment(b"six");
292        builder.push_segment(b"seven");
293
294        let as_vec = builder.to_vec();
295        let reference_vec = vec![
296            b"one".to_vec(),
297            b"two".to_vec(),
298            b"three".to_vec(),
299            b"four".to_vec(),
300            b"five".to_vec(),
301            b"six".to_vec(),
302            b"seven".to_vec(),
303        ];
304
305        assert_eq!(as_vec, reference_vec);
306        assert_eq!(builder.len(), reference_vec.len());
307    }
308}