reifydb_value/value/container/
varlen.rs1use std::{
5 fmt::{self, Debug},
6 result::Result as StdResult,
7};
8
9use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeSeq};
10use serde_bytes::{ByteBuf, Bytes};
11
12use crate::reifydb_assertions;
13
14pub struct VarlenContainer {
15 data: Vec<u8>,
16 offsets: Vec<u64>,
17}
18
19impl Clone for VarlenContainer {
20 fn clone(&self) -> Self {
21 Self {
22 data: self.data.clone(),
23 offsets: self.offsets.clone(),
24 }
25 }
26}
27
28impl Debug for VarlenContainer {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 f.debug_struct("VarlenContainer")
31 .field("len", &self.len())
32 .field("data_bytes", &self.data.len())
33 .finish()
34 }
35}
36
37impl PartialEq for VarlenContainer {
38 fn eq(&self, other: &Self) -> bool {
39 if self.len() != other.len() {
40 return false;
41 }
42 for i in 0..self.len() {
43 if self.get_bytes(i) != other.get_bytes(i) {
44 return false;
45 }
46 }
47 true
48 }
49}
50
51impl VarlenContainer {
52 pub fn from_byte_slices<'a, I>(items: I) -> Self
53 where
54 I: IntoIterator<Item = &'a [u8]>,
55 {
56 let mut offsets: Vec<u64> = vec![0];
57 let mut data: Vec<u8> = Vec::new();
58 for item in items {
59 data.extend_from_slice(item);
60 offsets.push(data.len() as u64);
61 }
62 Self {
63 data,
64 offsets,
65 }
66 }
67
68 pub fn from_repeated_bytes(item: &[u8], count: usize) -> Self {
69 let mut data: Vec<u8> = Vec::with_capacity(item.len() * count);
70 let mut offsets: Vec<u64> = Vec::with_capacity(count + 1);
71 offsets.push(0);
72 for _ in 0..count {
73 data.extend_from_slice(item);
74 offsets.push(data.len() as u64);
75 }
76 Self {
77 data,
78 offsets,
79 }
80 }
81
82 pub fn with_capacity(item_capacity: usize, data_capacity: usize) -> Self {
83 let mut offsets = Vec::with_capacity(item_capacity + 1);
84 offsets.push(0);
85 Self {
86 data: Vec::with_capacity(data_capacity),
87 offsets,
88 }
89 }
90
91 pub fn empty() -> Self {
92 Self {
93 data: Vec::new(),
94 offsets: vec![0],
95 }
96 }
97
98 pub fn from_raw_parts(data: Vec<u8>, offsets: Vec<u64>) -> Self {
99 reifydb_assertions! {
100 assert!(!offsets.is_empty(), "offsets must always have offsets[0] = 0");
101 assert_eq!(offsets[0], 0, "offsets[0] must be 0");
102 assert_eq!(*offsets.last().unwrap() as usize, data.len(), "offsets[len] must equal data.len()");
103 }
104 Self {
105 data,
106 offsets,
107 }
108 }
109}
110
111impl VarlenContainer {
112 pub fn from_storage_parts(data: Vec<u8>, offsets: Vec<u64>) -> Self {
113 reifydb_assertions! {
114 assert!(
115 !offsets.is_empty(),
116 "offsets must always include the leading 0; got empty offsets"
117 );
118 }
119 Self {
120 data,
121 offsets,
122 }
123 }
124
125 pub fn len(&self) -> usize {
126 self.offsets.len().saturating_sub(1)
127 }
128
129 pub fn is_empty(&self) -> bool {
130 self.len() == 0
131 }
132
133 pub fn data_byte_len(&self) -> usize {
134 self.data.len()
135 }
136
137 pub fn data_bytes(&self) -> &[u8] {
138 self.data.as_slice()
139 }
140
141 pub fn offsets(&self) -> &[u64] {
142 self.offsets.as_slice()
143 }
144
145 pub fn get_bytes(&self, idx: usize) -> Option<&[u8]> {
146 if idx >= self.len() {
147 return None;
148 }
149 let start = self.offsets.as_slice()[idx] as usize;
150 let end = self.offsets.as_slice()[idx + 1] as usize;
151 self.data.as_slice().get(start..end)
152 }
153
154 pub fn capacity(&self) -> usize {
155 self.offsets.capacity().saturating_sub(1)
156 }
157
158 pub fn heap_size(&self) -> usize {
159 self.data.capacity() + self.offsets.capacity() * size_of::<u64>()
160 }
161
162 pub fn data(&self) -> &Vec<u8> {
163 &self.data
164 }
165
166 pub fn offsets_data(&self) -> &Vec<u64> {
167 &self.offsets
168 }
169
170 pub fn clear_generic(&mut self) {
171 self.data.clear();
172 self.offsets.clear();
173 self.offsets.push(0u64);
174 }
175}
176
177impl VarlenContainer {
178 pub fn clear(&mut self) {
179 let data_mut = &mut self.data;
180 data_mut.clear();
181 let offsets_mut = &mut self.offsets;
182 offsets_mut.clear();
183 offsets_mut.push(0);
184 }
185
186 pub fn push_bytes(&mut self, bytes: &[u8]) {
187 let data_mut = &mut self.data;
188 data_mut.extend_from_slice(bytes);
189 let new_end = data_mut.len() as u64;
190 self.offsets.push(new_end);
191 }
192
193 pub fn extend_from(&mut self, other: &Self) {
194 let base = self.data.len() as u64;
195 let other_offsets = other.offsets.as_slice();
196 let other_data = other.data.as_slice();
197
198 let data_mut = &mut self.data;
199 data_mut.extend_from_slice(other_data);
200
201 let offsets_mut = &mut self.offsets;
202
203 offsets_mut.extend(other_offsets.iter().skip(1).map(|&o| base + o));
204 }
205
206 pub fn filter_in_place<F: FnMut(usize) -> bool>(&mut self, mut keep: F) {
207 let len = self.len();
208 let mut new_data = Vec::with_capacity(self.data_byte_len());
209 let mut new_offsets = Vec::with_capacity(len + 1);
210 new_offsets.push(0);
211 for i in 0..len {
212 if keep(i) {
213 let bytes = self.get_bytes(i).unwrap_or(&[]);
214 new_data.extend_from_slice(bytes);
215 new_offsets.push(new_data.len() as u64);
216 }
217 }
218 self.data = new_data;
219 self.offsets = new_offsets;
220 }
221
222 pub fn reorder_in_place(&mut self, indices: &[usize]) {
223 let mut new_data = Vec::with_capacity(self.data_byte_len());
224 let mut new_offsets = Vec::with_capacity(indices.len() + 1);
225 new_offsets.push(0);
226 for &idx in indices {
227 let bytes = self.get_bytes(idx).unwrap_or(&[]);
228 new_data.extend_from_slice(bytes);
229 new_offsets.push(new_data.len() as u64);
230 }
231 self.data = new_data;
232 self.offsets = new_offsets;
233 }
234
235 pub fn take_n(&self, n: usize) -> Self {
236 let n = n.min(self.len());
237 let end_byte = self.offsets.as_slice()[n] as usize;
238 let new_data: Vec<u8> = self.data.as_slice()[..end_byte].to_vec();
239 let new_offsets: Vec<u64> = self.offsets.as_slice()[..=n].to_vec();
240 Self::from_raw_parts(new_data, new_offsets)
241 }
242
243 pub fn slice(&self, start: usize, end: usize) -> Self {
244 let len = self.len();
245 let start = start.min(len);
246 let end = end.min(len);
247 if start >= end {
248 return Self::empty();
249 }
250 let start_byte = self.offsets.as_slice()[start] as usize;
251 let end_byte = self.offsets.as_slice()[end] as usize;
252 let new_data: Vec<u8> = self.data.as_slice()[start_byte..end_byte].to_vec();
253
254 let new_offsets: Vec<u64> =
255 self.offsets.as_slice()[start..=end].iter().map(|o| *o - start_byte as u64).collect();
256 Self::from_raw_parts(new_data, new_offsets)
257 }
258}
259
260impl Serialize for VarlenContainer {
261 fn serialize<Ser: Serializer>(&self, serializer: Ser) -> StdResult<Ser::Ok, Ser::Error> {
262 let mut seq = serializer.serialize_seq(Some(self.len()))?;
263 for i in 0..self.len() {
264 let bytes = self.get_bytes(i).unwrap_or(&[]);
265 seq.serialize_element(Bytes::new(bytes))?;
266 }
267 seq.end()
268 }
269}
270
271impl<'de> Deserialize<'de> for VarlenContainer {
272 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
273 let items: Vec<ByteBuf> = Vec::deserialize(deserializer)?;
274 let total: usize = items.iter().map(|b| b.len()).sum();
275 let mut data = Vec::with_capacity(total);
276 let mut offsets = Vec::with_capacity(items.len() + 1);
277 offsets.push(0);
278 for item in items {
279 data.extend_from_slice(item.as_slice());
280 offsets.push(data.len() as u64);
281 }
282 Ok(Self::from_raw_parts(data, offsets))
283 }
284}
285
286impl Default for VarlenContainer {
287 fn default() -> Self {
288 Self::empty()
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use postcard::{from_bytes as postcard_from_bytes, to_allocvec as postcard_to_allocvec};
295
296 use super::*;
297
298 #[test]
299 fn empty_has_zero_len_and_offsets_with_one_zero() {
300 let c = VarlenContainer::empty();
301 assert_eq!(c.len(), 0);
302 assert_eq!(c.offsets(), &[0u64]);
303 assert!(c.data_bytes().is_empty());
304 }
305
306 #[test]
307 fn push_bytes_appends_and_updates_offsets() {
308 let mut c = VarlenContainer::empty();
309 c.push_bytes(b"hello");
310 c.push_bytes(b"");
311 c.push_bytes(b"world");
312 assert_eq!(c.len(), 3);
313 assert_eq!(c.offsets(), &[0u64, 5, 5, 10]);
314 assert_eq!(c.data_bytes(), b"helloworld");
315 assert_eq!(c.get_bytes(0), Some(b"hello".as_slice()));
316 assert_eq!(c.get_bytes(1), Some(b"".as_slice()));
317 assert_eq!(c.get_bytes(2), Some(b"world".as_slice()));
318 assert_eq!(c.get_bytes(3), None);
319 }
320
321 #[test]
322 fn from_byte_slices_round_trip() {
323 let c = VarlenContainer::from_byte_slices([b"a".as_slice(), b"bc", b"def"]);
324 assert_eq!(c.len(), 3);
325 assert_eq!(c.data_bytes(), b"abcdef");
326 assert_eq!(c.offsets(), &[0u64, 1, 3, 6]);
327 }
328
329 #[test]
330 fn from_repeated_bytes_matches_explicit_copies() {
331 let repeated = VarlenContainer::from_repeated_bytes(b"abc", 3);
332 let explicit = VarlenContainer::from_byte_slices([b"abc".as_slice(), b"abc", b"abc"]);
333 assert_eq!(repeated, explicit);
334 assert_eq!(repeated.len(), 3);
335 assert_eq!(repeated.data_bytes(), b"abcabcabc");
336 assert_eq!(repeated.offsets(), &[0u64, 3, 6, 9]);
337 }
338
339 #[test]
340 fn from_repeated_bytes_zero_count_is_empty() {
341 let c = VarlenContainer::from_repeated_bytes(b"abc", 0);
342 assert_eq!(c.len(), 0);
343 assert_eq!(c.offsets(), &[0u64]);
344 assert!(c.data_bytes().is_empty());
345 }
346
347 #[test]
348 fn from_repeated_bytes_empty_item_keeps_count() {
349 let c = VarlenContainer::from_repeated_bytes(b"", 4);
350 assert_eq!(c.len(), 4);
351 assert_eq!(c.get_bytes(0), Some(b"".as_slice()));
352 assert_eq!(c.get_bytes(3), Some(b"".as_slice()));
353 assert!(c.data_bytes().is_empty());
354 }
355
356 #[test]
357 fn clear_resets_to_empty_state() {
358 let mut c = VarlenContainer::from_byte_slices([b"x".as_slice(), b"y"]);
359 c.clear();
360 assert_eq!(c.len(), 0);
361 assert_eq!(c.offsets(), &[0u64]);
362 assert!(c.data_bytes().is_empty());
363 }
364
365 #[test]
366 fn extend_from_concatenates_and_rebases_offsets() {
367 let mut a = VarlenContainer::from_byte_slices([b"foo".as_slice()]);
368 let b = VarlenContainer::from_byte_slices([b"bar".as_slice(), b"baz"]);
369 a.extend_from(&b);
370 assert_eq!(a.len(), 3);
371 assert_eq!(a.data_bytes(), b"foobarbaz");
372 assert_eq!(a.offsets(), &[0u64, 3, 6, 9]);
373 }
374
375 #[test]
376 fn filter_in_place_keeps_matching_elements() {
377 let mut c = VarlenContainer::from_byte_slices([b"yes".as_slice(), b"no", b"yes", b"no"]);
378 c.filter_in_place(|i| i % 2 == 0);
379 assert_eq!(c.len(), 2);
380 assert_eq!(c.get_bytes(0), Some(b"yes".as_slice()));
381 assert_eq!(c.get_bytes(1), Some(b"yes".as_slice()));
382 }
383
384 #[test]
385 fn reorder_in_place_handles_oob_as_empty() {
386 let mut c = VarlenContainer::from_byte_slices([b"a".as_slice(), b"b"]);
387 c.reorder_in_place(&[1, 100, 0]);
388 assert_eq!(c.len(), 3);
389 assert_eq!(c.get_bytes(0), Some(b"b".as_slice()));
390 assert_eq!(c.get_bytes(1), Some(b"".as_slice()));
391 assert_eq!(c.get_bytes(2), Some(b"a".as_slice()));
392 }
393
394 #[test]
395 fn take_n_truncates() {
396 let c = VarlenContainer::from_byte_slices([b"a".as_slice(), b"b", b"c"]);
397 let t = c.take_n(2);
398 assert_eq!(t.len(), 2);
399 assert_eq!(t.get_bytes(0), Some(b"a".as_slice()));
400 assert_eq!(t.get_bytes(1), Some(b"b".as_slice()));
401 }
402
403 #[test]
404 fn slice_extracts_subrange_with_rebased_offsets() {
405 let c = VarlenContainer::from_byte_slices([b"aa".as_slice(), b"bb", b"cc", b"dd"]);
406 let s = c.slice(1, 3);
407 assert_eq!(s.len(), 2);
408 assert_eq!(s.get_bytes(0), Some(b"bb".as_slice()));
409 assert_eq!(s.get_bytes(1), Some(b"cc".as_slice()));
410 assert_eq!(s.offsets(), &[0u64, 2, 4]);
411 }
412
413 #[test]
414 fn serde_round_trip_preserves_content() {
415 let original = VarlenContainer::from_byte_slices([b"hello".as_slice(), b"", b"world"]);
416 let encoded: Vec<u8> = postcard_to_allocvec(&original).unwrap();
417 let decoded: VarlenContainer = postcard_from_bytes(&encoded).unwrap();
418 assert_eq!(decoded.len(), 3);
419 assert_eq!(decoded.get_bytes(0), Some(b"hello".as_slice()));
420 assert_eq!(decoded.get_bytes(1), Some(b"".as_slice()));
421 assert_eq!(decoded.get_bytes(2), Some(b"world".as_slice()));
422 }
423
424 #[test]
425 fn serde_wire_compat_with_vec_of_strings() {
426 let strings = vec!["a".to_string(), "bc".to_string(), "def".to_string()];
429 let encoded: Vec<u8> = postcard_to_allocvec(&strings).unwrap();
430 let decoded: VarlenContainer = postcard_from_bytes(&encoded).unwrap();
431 assert_eq!(decoded.len(), 3);
432 assert_eq!(decoded.get_bytes(0), Some(b"a".as_slice()));
433 assert_eq!(decoded.get_bytes(1), Some(b"bc".as_slice()));
434 assert_eq!(decoded.get_bytes(2), Some(b"def".as_slice()));
435 }
436
437 #[test]
438 fn equality_compares_logical_content() {
439 let a = VarlenContainer::from_byte_slices([b"x".as_slice(), b"y"]);
440 let b = VarlenContainer::from_byte_slices([b"x".as_slice(), b"y"]);
441 assert_eq!(a, b);
442 }
443}