drive/util/object_size_info/
path_info.rs1use 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#[derive(Clone, Debug)]
15pub enum PathInfo<'a, const N: usize> {
16 PathFixedSizeArray([&'a [u8]; N]),
18
19 PathAsVec(Vec<Vec<u8>>),
21
22 PathWithSizes(KeyInfoPath),
24}
25
26impl<'a, const N: usize> PathInfo<'a, N> {
27 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 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 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 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 p.push(DriveKeyInfo::Key(vec![1])).expect("push key");
174 let bytes = [2u8];
176 p.push(DriveKeyInfo::KeyRef(&bytes)).expect("push ref");
177 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}