Skip to main content

drive/util/object_size_info/
path_info.rs

1use grovedb::batch::key_info::KeyInfo::KnownKey;
2use grovedb::batch::KeyInfoPath;
3
4use grovedb_storage::worst_case_costs::WorstKeyLength;
5
6use DriveKeyInfo::{Key, KeyRef, KeySize};
7use PathInfo::{PathAsVec, PathFixedSizeArray, PathWithSizes};
8
9use crate::error::drive::DriveError;
10use crate::error::Error;
11use crate::util::object_size_info::drive_key_info::DriveKeyInfo;
12
13/// Info about a path.
14#[derive(Clone, Debug)]
15pub enum PathInfo<'a, const N: usize> {
16    /// An into iter Path
17    PathFixedSizeArray([&'a [u8]; N]),
18
19    /// An into iter Path
20    PathAsVec(Vec<Vec<u8>>),
21
22    /// A path size
23    PathWithSizes(KeyInfoPath),
24}
25
26impl<'a, const N: usize> PathInfo<'a, N> {
27    /// Returns the length of the path as a usize.
28    pub fn len(&self) -> u32 {
29        match self {
30            PathFixedSizeArray(path_iterator) => {
31                (*path_iterator).into_iter().map(|a| a.len() as u32).sum()
32            }
33            PathAsVec(path_iterator) => path_iterator.iter().map(|a| a.len() as u32).sum(),
34            PathWithSizes(path_size) => path_size.iterator().map(|a| a.max_length() as u32).sum(),
35        }
36    }
37
38    /// Returns true if the path is empty.
39    pub fn is_empty(&self) -> bool {
40        match self {
41            PathFixedSizeArray(path_iterator) => (*path_iterator).is_empty(),
42            PathAsVec(path_iterator) => path_iterator.is_empty(),
43            PathWithSizes(path_size) => path_size.is_empty(),
44        }
45    }
46
47    /// Pushes the given key into the path.
48    pub fn push(&mut self, key_info: DriveKeyInfo<'a>) -> Result<(), Error> {
49        match self {
50            PathFixedSizeArray(_) => {
51                return Err(Error::Drive(DriveError::CorruptedCodeExecution(
52                    "can not add a key to a fixed size path iterator",
53                )))
54            }
55            PathAsVec(path_iterator) => match key_info {
56                Key(key) => path_iterator.push(key),
57                KeyRef(key_ref) => path_iterator.push(key_ref.to_vec()),
58                KeySize(..) => {
59                    return Err(Error::Drive(DriveError::CorruptedCodeExecution(
60                        "can not add a key size to path iterator",
61                    )))
62                }
63            },
64            PathWithSizes(key_info_path) => match key_info {
65                Key(key) => key_info_path.push(KnownKey(key)),
66                KeyRef(key_ref) => key_info_path.push(KnownKey(key_ref.to_vec())),
67                KeySize(key_info) => key_info_path.push(key_info),
68            },
69        }
70        Ok(())
71    }
72
73    /// Get the KeyInfoPath for grovedb estimated costs
74    pub(crate) fn convert_to_key_info_path(self) -> KeyInfoPath {
75        match self {
76            PathFixedSizeArray(path) => KeyInfoPath::from_known_path(path),
77            PathAsVec(path) => KeyInfoPath::from_known_owned_path(path),
78            PathWithSizes(key_info_path) => key_info_path,
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86    use grovedb::batch::key_info::KeyInfo::MaxKeySize;
87
88    #[test]
89    fn fixed_size_array_len_sums_elements() {
90        let arr: [&[u8]; 3] = [&[1u8], &[2u8, 3u8], &[4u8, 5u8, 6u8]];
91        let p: PathInfo<3> = PathInfo::PathFixedSizeArray(arr);
92        assert_eq!(p.len(), 6);
93        assert!(!p.is_empty());
94    }
95
96    #[test]
97    fn fixed_size_empty_array_reports_zero_len() {
98        let arr: [&[u8]; 0] = [];
99        let p: PathInfo<0> = PathInfo::PathFixedSizeArray(arr);
100        assert_eq!(p.len(), 0);
101        assert!(p.is_empty());
102    }
103
104    #[test]
105    fn as_vec_len_and_empty() {
106        let p: PathInfo<0> = PathInfo::PathAsVec(vec![vec![1u8, 2], vec![3u8]]);
107        assert_eq!(p.len(), 3);
108        assert!(!p.is_empty());
109
110        let p: PathInfo<0> = PathInfo::PathAsVec(vec![]);
111        assert!(p.is_empty());
112        assert_eq!(p.len(), 0);
113    }
114
115    #[test]
116    fn with_sizes_len_uses_max_length() {
117        let path = KeyInfoPath::from_known_path([b"abc".as_ref(), b"defg".as_ref()]);
118        let p: PathInfo<0> = PathInfo::PathWithSizes(path);
119        assert_eq!(p.len(), 7);
120        assert!(!p.is_empty());
121    }
122
123    #[test]
124    fn push_to_fixed_size_errors() {
125        let arr: [&[u8]; 1] = [&[1u8]];
126        let mut p: PathInfo<1> = PathInfo::PathFixedSizeArray(arr);
127        let err = p.push(DriveKeyInfo::Key(vec![9])).expect_err("err");
128        match err {
129            Error::Drive(DriveError::CorruptedCodeExecution(msg)) => {
130                assert!(msg.contains("fixed size"));
131            }
132            _ => panic!("expected CorruptedCodeExecution"),
133        }
134    }
135
136    #[test]
137    fn push_key_to_vec_appends_vec() {
138        let mut p: PathInfo<0> = PathInfo::PathAsVec(vec![]);
139        p.push(DriveKeyInfo::Key(vec![1, 2])).expect("push");
140        let bytes: [u8; 1] = [3];
141        p.push(DriveKeyInfo::KeyRef(&bytes)).expect("push ref");
142        match p {
143            PathInfo::PathAsVec(v) => {
144                assert_eq!(v, vec![vec![1u8, 2], vec![3u8]]);
145            }
146            _ => panic!("expected vec"),
147        }
148    }
149
150    #[test]
151    fn push_key_size_to_vec_errors() {
152        let mut p: PathInfo<0> = PathInfo::PathAsVec(vec![]);
153        let err = p
154            .push(DriveKeyInfo::KeySize(MaxKeySize {
155                unique_id: vec![],
156                max_size: 4,
157            }))
158            .expect_err("should err");
159        match err {
160            Error::Drive(DriveError::CorruptedCodeExecution(msg)) => {
161                assert!(msg.contains("key size"));
162            }
163            _ => panic!("expected CorruptedCodeExecution"),
164        }
165    }
166
167    #[test]
168    fn push_all_variants_to_path_with_sizes() {
169        let mut p: PathInfo<0> =
170            PathInfo::PathWithSizes(KeyInfoPath::from_known_owned_path(vec![]));
171
172        // Key
173        p.push(DriveKeyInfo::Key(vec![1])).expect("push key");
174        // KeyRef
175        let bytes = [2u8];
176        p.push(DriveKeyInfo::KeyRef(&bytes)).expect("push ref");
177        // KeySize
178        p.push(DriveKeyInfo::KeySize(MaxKeySize {
179            unique_id: vec![0xA],
180            max_size: 3,
181        }))
182        .expect("push size");
183
184        match p {
185            PathInfo::PathWithSizes(kip) => assert_eq!(kip.len(), 3),
186            _ => panic!("expected PathWithSizes"),
187        }
188    }
189
190    #[test]
191    fn convert_to_key_info_path_fixed_size_array() {
192        let arr: [&[u8]; 2] = [&[1u8], &[2u8, 3u8]];
193        let p: PathInfo<2> = PathInfo::PathFixedSizeArray(arr);
194        let kip = p.convert_to_key_info_path();
195        assert_eq!(kip.len(), 2);
196    }
197
198    #[test]
199    fn convert_to_key_info_path_as_vec() {
200        let p: PathInfo<0> = PathInfo::PathAsVec(vec![vec![1], vec![2, 3]]);
201        let kip = p.convert_to_key_info_path();
202        assert_eq!(kip.len(), 2);
203    }
204
205    #[test]
206    fn convert_to_key_info_path_passthrough() {
207        let orig = KeyInfoPath::from_known_path([b"x".as_ref()]);
208        let p: PathInfo<0> = PathInfo::PathWithSizes(orig);
209        let kip = p.convert_to_key_info_path();
210        assert_eq!(kip.len(), 1);
211    }
212}