seq_str/
seq_bytes.rs

1use alloc::vec::Vec;
2use core::fmt;
3
4/// A sequence of `&[u8]`, stored contiguously
5///
6/// This can be used as a drop-in replacement for `Vec<Vec<u8>>` in some cases,
7/// with better memory locality and fewer memory allocations.
8///
9/// When using `SeqBytes` instead of `Vec<Vec<u8>>`, the individual byte strings
10/// cannot be resized, but when this isn't needed there isn't much downside otherwise.
11///
12/// The container also supports "emplace"-style APIs like `in_place_writer`, which allow you to
13/// write the next element directly into the contiguous buffer with minimal overhead.
14#[derive(Clone, Default, Eq, PartialEq, Hash)]
15pub struct SeqBytes {
16    data: Vec<u8>,
17    offsets: Vec<usize>,
18}
19
20impl SeqBytes {
21    /// Create a new SeqBytes
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    /// Check if the sequence is empty
27    pub fn is_empty(&self) -> bool {
28        self.len() == 0
29    }
30
31    /// Get the number of slices in the sequence
32    pub fn len(&self) -> usize {
33        self.offsets.len()
34    }
35
36    /// Reserve capacity for more slices
37    pub fn reserve(&mut self, extra: usize) {
38        self.offsets.reserve(extra);
39        // Guess how much data to reserve based on existing usage
40        if !self.is_empty() && extra > 0 {
41            let a = extra * 4;
42            let b = self.data.len() * 4;
43            // estimate data.len * extra / offsets.len
44            let c = (self.data.len() * extra)
45                >> ((usize::BITS - 1) - self.offsets.len().leading_zeros());
46
47            #[allow(clippy::collapsible_else_if)]
48            let median = if a <= b {
49                if a <= c { core::cmp::min(b, c) } else { a }
50            } else {
51                if a <= c { a } else { core::cmp::max(b, c) }
52            };
53
54            self.data.reserve(median);
55        } else {
56            self.data.reserve(4 * extra);
57        }
58    }
59
60    /// Shrink container to fit the current data
61    pub fn shrink_to_fit(&mut self) {
62        self.data.shrink_to_fit();
63        self.offsets.shrink_to_fit();
64    }
65
66    /// Get the i'th element of the sequence in a checked manner
67    pub fn get(&self, idx: usize) -> Option<&[u8]> {
68        let first = self.offsets.get(idx)?;
69        match self.offsets.get(idx + 1) {
70            Some(second) => Some(&self.data[*first..*second]),
71            None => Some(&self.data[*first..]),
72        }
73    }
74
75    /// Get the i'th element of the sequence in a checked manner
76    pub fn get_mut(&mut self, idx: usize) -> Option<&mut [u8]> {
77        let first = self.offsets.get(idx)?;
78        match self.offsets.get(idx + 1) {
79            Some(second) => Some(&mut self.data[*first..*second]),
80            None => Some(&mut self.data[*first..]),
81        }
82    }
83
84    /// Check if the sequence contains a particular element
85    pub fn contains(&self, s: impl AsRef<[u8]>) -> bool {
86        let s = s.as_ref();
87        self.iter().any(|b| b == s)
88    }
89
90    /// Push a &[u8] onto the sequence
91    pub fn push(&mut self, s: impl AsRef<[u8]>) {
92        self.offsets.push(self.data.len());
93        self.data.extend(s.as_ref().iter());
94    }
95
96    /// Get the last &[u8] of the sequence
97    pub fn last(&self) -> Option<&[u8]> {
98        match self.offsets.last() {
99            Some(o) => Some(&self.data[*o..]),
100            None => None,
101        }
102    }
103
104    /// Pop the last element of the container
105    /// Note that we can't return it because of lifetimes, so call [last] before popping.
106    pub fn pop(&mut self) {
107        if let Some(o) = self.offsets.pop() {
108            self.data.truncate(o);
109        }
110    }
111
112    /// Iterate over the sequence of &[u8]
113    pub fn iter(&self) -> SeqBytesIter<'_> // impl ExactSizeIterator<Item = &[u8]>
114    {
115        SeqBytesIter {
116            data: &self.data[..],
117            offsets: &self.offsets[..],
118        }
119    }
120
121    /// Iterate over the sequence of &mut [u8]
122    pub fn iter_mut(&mut self) -> SeqBytesIterMut<'_> // impl ExactSizeIterator<Item = &mut[u8]>
123    {
124        SeqBytesIterMut {
125            data: &mut self.data[..],
126            offsets: &self.offsets[..],
127        }
128    }
129
130    // Helper to convert range bounds object to a range
131    fn range_bounds_to_range(
132        &self,
133        range_bounds: impl core::ops::RangeBounds<usize>,
134    ) -> (usize, usize) {
135        use core::ops::Bound;
136
137        let start_idx = match range_bounds.start_bound() {
138            Bound::Included(s) => *s,
139            Bound::Excluded(s) => s + 1,
140            Bound::Unbounded => 0,
141        };
142
143        let end_idx = match range_bounds.end_bound() {
144            Bound::Included(e) => e + 1,
145            Bound::Excluded(e) => *e,
146            Bound::Unbounded => self.offsets.len(),
147        };
148
149        (start_idx, end_idx)
150    }
151
152    /// Iterate over a range of the sequence of `&[u8]`
153    ///
154    /// This resembles [std::collections::BTreeMap::range], and is needed becuase like `BTreeMap`,
155    /// we can't implement `Deref` or `SliceIndex<Range>` and produce a slice of our contents.
156    /// See also [as_vec].
157    pub fn range(&self, range_bounds: impl core::ops::RangeBounds<usize>) -> SeqBytesIter<'_> {
158        let (start_idx, end_idx) = self.range_bounds_to_range(range_bounds);
159        let data_end = self
160            .offsets
161            .get(end_idx)
162            .cloned()
163            .unwrap_or(self.data.len());
164
165        SeqBytesIter {
166            data: &self.data[0..data_end],
167            offsets: &self.offsets[start_idx..end_idx],
168        }
169    }
170
171    /// Iterate over a range of the sequence of `&mut [u8]`
172    pub fn range_mut(
173        &mut self,
174        range_bounds: impl core::ops::RangeBounds<usize>,
175    ) -> SeqBytesIterMut<'_> {
176        let (start_idx, end_idx) = self.range_bounds_to_range(range_bounds);
177        let data_end = self
178            .offsets
179            .get(end_idx)
180            .cloned()
181            .unwrap_or(self.data.len());
182
183        SeqBytesIterMut {
184            data: &mut self.data[0..data_end],
185            offsets: &self.offsets[start_idx..end_idx],
186        }
187    }
188
189    /// Truncate to at most the first n slices
190    pub fn truncate(&mut self, new_size: usize) {
191        if let Some(off) = self.offsets.get(new_size) {
192            self.data.truncate(*off);
193            self.offsets.truncate(new_size);
194        }
195    }
196
197    /// Resize to contain only the first n `&[u8]`, or pad up to n slices, with empty slices added
198    pub fn resize(&mut self, new_size: usize) {
199        if let Some(off) = self.offsets.get(new_size) {
200            self.data.truncate(*off);
201            self.offsets.truncate(new_size);
202        } else {
203            // Push empty slices until offsets has length new_size
204            let d = new_size - self.offsets.len();
205            self.offsets.reserve(d);
206            for _ in 0..d {
207                self.offsets.push(self.data.len());
208            }
209        }
210    }
211
212    /// Retain only those slices satisfying a predicate.
213    /// The slices are always visited in order, similar to [std::vec::Vec::retain].
214    pub fn retain(&mut self, mut pred: impl FnMut(&[u8]) -> bool) {
215        self.retain_mut(|elem| pred(elem))
216    }
217
218    /// Retain only those slices satisfying a predicate.
219    /// The slices are always visited in order, similar to [std::vec::Vec::retain_mut].
220    pub fn retain_mut(&mut self, mut pred: impl FnMut(&mut [u8]) -> bool) {
221        let (data, offsets) = (&mut self.data, &mut self.offsets);
222
223        let mut offset_write_idx = 0;
224        let mut kept_bytes = 0;
225
226        // Invariant:
227        // Offsets is not reduced in length during this loop
228        // Data is not reduced in length during this loop
229        for offset_idx in 0..offsets.len() {
230            let start = offsets[offset_idx];
231            let end = offsets.get(offset_idx + 1).cloned().unwrap_or(data.len());
232
233            let outcome = pred(&mut data[start..end]);
234            if outcome {
235                // We will preserve kept_len additional bytes,
236                // write their starting offset first.
237                let kept_len = end - start;
238                offsets[offset_write_idx] = kept_bytes;
239                offset_write_idx += 1;
240
241                // Move from data[start..end] to
242                // data[kept_bytes, kept_bytes + kept_len]
243                // if start == kept bytes we don't have to do anything
244                if kept_bytes != start {
245                    for byte_idx in 0..kept_len {
246                        data[kept_bytes + byte_idx] = data[start + byte_idx];
247                    }
248                }
249                kept_bytes += kept_len;
250            }
251        }
252        drop(pred);
253
254        // Truncate both offsets and data to what was actually retained
255        offsets.truncate(offset_write_idx);
256        data.truncate(kept_bytes);
257    }
258
259    /// Get an `impl std::io::Write` which can be used to write the next slice
260    /// directly into the buffer without copying.
261    #[cfg(feature = "std")]
262    pub fn in_place_writer(&mut self) -> impl std::io::Write {
263        // Correctness:
264        // If we push a new offset on, then we have conceptually added a new string.
265        // If the only thing that happens after that is that data is appended to self.data,
266        // then the final state is correct and offsets doesn't need further adjusting.
267        //
268        // The only thing they can do with std::io::Write is push more bytes.
269        // And no other changes can be made to SeqBytes until that writer is dropped,
270        // because it captures &mut self.
271        //
272        // So we don't need to return an object with a Drop impl, we will always end
273        // up in the correct state.
274        self.offsets.push(self.data.len());
275        &mut self.data
276    }
277
278    /// Version of `in_place_writer` that doesn't require `std::io::Write` trait
279    ///
280    /// Any bytes passed to the result of this function get concatenated to produce the
281    /// newest byte string in the sequence. The new item is final when the writer is dropped.
282    pub fn in_place_writer_no_std(&mut self) -> impl FnMut(&[u8]) {
283        self.offsets.push(self.data.len());
284
285        let dat = &mut self.data;
286
287        move |b: &[u8]| {
288            dat.extend(b);
289        }
290    }
291
292    /// Express as a Vec<&[u8]>. The main reason that this may be useful is that there are
293    /// useful methods on slice types `&[&[u8]]`, for example, [core::slice::binary_search],
294    /// but `SeqBytes` itself doesn't implement `Deref` the way that `Vec` does and can
295    /// only produce such a slice by allocating.
296    ///
297    /// Note: The trade-offs are that we would need more memory and `in_place_writer` would have
298    /// to be more complicated and slower if we wanted our internal representation of the offsets
299    /// to be a `Vec<&[u8]>`, which would allow such a `Deref` implementation.
300    /// The direction we've taken is to add useful functions from `Vec` and slice
301    /// as needed directly to this type instead, if they can't be obtained in a simpler way.
302    pub fn as_vec(&self) -> Vec<&[u8]> {
303        self.iter().collect()
304    }
305}
306
307impl core::ops::Index<usize> for SeqBytes {
308    type Output = [u8];
309
310    fn index(&self, index: usize) -> &[u8] {
311        let first = self.offsets[index];
312        match self.offsets.get(index + 1) {
313            Some(second) => &self.data[first..*second],
314            None => &self.data[first..],
315        }
316    }
317}
318
319impl core::ops::IndexMut<usize> for SeqBytes {
320    fn index_mut(&mut self, index: usize) -> &mut [u8] {
321        let first = self.offsets[index];
322        match self.offsets.get(index + 1) {
323            Some(second) => &mut self.data[first..*second],
324            None => &mut self.data[first..],
325        }
326    }
327}
328
329impl fmt::Debug for SeqBytes {
330    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331        f.debug_list().entries(self.iter()).finish()
332    }
333}
334
335/// An iterator over a SeqBytes object
336pub struct SeqBytesIter<'a> {
337    data: &'a [u8],
338    offsets: &'a [usize],
339}
340
341impl<'a> Iterator for SeqBytesIter<'a> {
342    type Item = &'a [u8];
343
344    fn next(&mut self) -> Option<&'a [u8]> {
345        let first = self.offsets.first()?;
346        self.offsets = &self.offsets[1..];
347
348        let second = self.offsets.first().cloned().unwrap_or(self.data.len());
349        Some(&self.data[*first..second])
350    }
351
352    fn size_hint(&self) -> (usize, Option<usize>) {
353        let remaining = self.offsets.len();
354        (remaining, Some(remaining))
355    }
356}
357
358impl<'a> ExactSizeIterator for SeqBytesIter<'a> {}
359
360impl<'a> DoubleEndedIterator for SeqBytesIter<'a> {
361    fn next_back(&mut self) -> Option<&'a [u8]> {
362        let last = *self.offsets.last()?;
363        self.offsets = &self.offsets[..self.offsets.len() - 1];
364
365        let (left, right) = self.data.split_at(last);
366        self.data = left;
367
368        Some(right)
369    }
370}
371
372/// A mutable iterator over a SeqBytes object
373pub struct SeqBytesIterMut<'a> {
374    data: &'a mut [u8],
375    offsets: &'a [usize],
376}
377
378impl<'a> Iterator for SeqBytesIterMut<'a> {
379    type Item = &'a mut [u8];
380
381    fn next(&mut self) -> Option<&'a mut [u8]> {
382        let first = self.offsets.first()?;
383        self.offsets = &self.offsets[1..];
384
385        let second = self.offsets.first().cloned().unwrap_or(self.data.len());
386
387        // Some(&mut self.data[*first..second])
388        // Work around borrow checker issue
389        let slice = unsafe {
390            let start = self.data.as_mut_ptr().add(*first);
391            core::slice::from_raw_parts_mut(start, second - first)
392        };
393
394        Some(slice)
395    }
396
397    fn size_hint(&self) -> (usize, Option<usize>) {
398        let remaining = self.offsets.len();
399        (remaining, Some(remaining))
400    }
401}
402
403impl<'a> ExactSizeIterator for SeqBytesIterMut<'a> {}
404
405impl<'a> DoubleEndedIterator for SeqBytesIterMut<'a> {
406    fn next_back(&mut self) -> Option<&'a mut [u8]> {
407        let last = *self.offsets.last()?;
408        self.offsets = &self.offsets[..self.offsets.len() - 1];
409
410        let (left, right) = self.data.split_at_mut(last);
411        // Work around borrow checker issue
412        self.data = unsafe {
413            let len = left.len();
414            let ptr = left.as_mut_ptr();
415            core::slice::from_raw_parts_mut(ptr, len)
416        };
417
418        // Work around borrow checker issue
419        let slice = unsafe {
420            let len = right.len();
421            let ptr = right.as_mut_ptr();
422            core::slice::from_raw_parts_mut(ptr, len)
423        };
424
425        Some(slice)
426    }
427}
428
429impl<A: AsRef<[u8]>> Extend<A> for SeqBytes {
430    fn extend<T>(&mut self, iter: T)
431    where
432        T: IntoIterator<Item = A>,
433    {
434        let iter = iter.into_iter();
435        self.reserve(iter.size_hint().0);
436        for item in iter {
437            self.push(item);
438        }
439    }
440}
441
442impl<A: AsRef<[u8]>> FromIterator<A> for SeqBytes {
443    // Required method
444    fn from_iter<T>(iter: T) -> Self
445    where
446        T: IntoIterator<Item = A>,
447    {
448        let mut result = SeqBytes::default();
449        result.extend(iter);
450        result
451    }
452}
453
454// IntoIterator can only be implemented for &'a SeqBytes,
455// otherwise the buffer doesn't live long enough.
456impl<'a> IntoIterator for &'a SeqBytes {
457    type Item = &'a [u8];
458    type IntoIter = SeqBytesIter<'a>;
459
460    fn into_iter(self) -> Self::IntoIter {
461        self.iter()
462    }
463}
464
465#[cfg(test)]
466mod tests {
467    use super::*;
468    use alloc::{borrow::ToOwned, vec};
469
470    #[test]
471    fn vec_slice_conversions() {
472        let vec_b = vec![b"1", b"2", b"3"];
473
474        let seq_b: SeqBytes = vec_b.into_iter().collect();
475
476        assert_eq!(seq_b.len(), 3);
477        assert_eq!(&seq_b[0], b"1");
478        assert_eq!(&seq_b[1], b"2");
479        assert_eq!(&seq_b[2], b"3");
480
481        let vec_str2 = seq_b.iter().map(ToOwned::to_owned).collect::<Vec<_>>();
482
483        assert_eq!(vec_str2.len(), 3);
484        assert_eq!(vec_str2[0], b"1");
485        assert_eq!(vec_str2[1], b"2");
486        assert_eq!(vec_str2[2], b"3");
487    }
488
489    #[test]
490    fn vec_vec_b_conversions() {
491        let vec_string = vec![b"1".to_owned(), b"2".to_owned(), b"3".to_owned()];
492
493        let seq_b: SeqBytes = vec_string.into_iter().collect();
494
495        assert_eq!(seq_b.len(), 3);
496        assert_eq!(&seq_b[0], b"1");
497        assert_eq!(&seq_b[1], b"2");
498        assert_eq!(&seq_b[2], b"3");
499
500        let vec_str2 = seq_b.iter().map(ToOwned::to_owned).collect::<Vec<_>>();
501
502        assert_eq!(vec_str2.len(), 3);
503        assert_eq!(vec_str2[0], b"1");
504        assert_eq!(vec_str2[1], b"2");
505        assert_eq!(vec_str2[2], b"3");
506    }
507
508    #[test]
509    fn iter_rev() {
510        let vec_b = vec![b"1", b"2", b"3"];
511
512        let seq_b: SeqBytes = vec_b.into_iter().collect();
513
514        assert_eq!(seq_b.len(), 3);
515        assert_eq!(&seq_b[0], b"1");
516        assert_eq!(&seq_b[1], b"2");
517        assert_eq!(&seq_b[2], b"3");
518
519        let seq_b2: SeqBytes = seq_b.into_iter().rev().collect();
520
521        assert_eq!(seq_b2.len(), 3);
522        assert_eq!(&seq_b2[0], b"3");
523        assert_eq!(&seq_b2[1], b"2");
524        assert_eq!(&seq_b2[2], b"1");
525    }
526
527    #[test]
528    fn contains() {
529        let vec_b: Vec<&[u8]> = vec![b"123", b"45", b"6", b"", b"7", b"89"];
530        let seq_b: SeqBytes = vec_b.iter().collect();
531
532        assert!(seq_b.contains(b"123"));
533        assert!(!seq_b.contains(b"12"));
534        assert!(!seq_b.contains(b"1"));
535        assert!(seq_b.contains(b""));
536        assert!(seq_b.contains(b"6"));
537    }
538
539    #[test]
540    fn iter_mut() {
541        let vec_b: Vec<&[u8]> = vec![b"123", b"45", b"6", b"", b"7", b"89"];
542        let mut seq_b: SeqBytes = vec_b.iter().collect();
543
544        for b in seq_b.iter_mut() {
545            if b.len() > 0 {
546                b[0] = b"a"[0];
547            }
548        }
549
550        assert_eq!(seq_b.len(), 6);
551        assert_eq!(&seq_b[0], b"a23");
552        assert_eq!(&seq_b[1], b"a5");
553        assert_eq!(&seq_b[2], b"a");
554        assert_eq!(&seq_b[3], b"");
555        assert_eq!(&seq_b[4], b"a");
556        assert_eq!(&seq_b[5], b"a9");
557    }
558
559    #[test]
560    fn retain() {
561        let vec_b: Vec<&[u8]> = vec![b"123", b"45", b"6", b"", b"7", b"89"];
562        let mut seq_b: SeqBytes = vec_b.iter().collect();
563
564        assert_eq!(seq_b.len(), 6);
565        assert_eq!(&seq_b[0], b"123");
566        assert_eq!(&seq_b[1], b"45");
567        assert_eq!(&seq_b[2], b"6");
568        assert_eq!(&seq_b[3], b"");
569        assert_eq!(&seq_b[4], b"7");
570        assert_eq!(&seq_b[5], b"89");
571
572        seq_b.retain(|b| !b.is_empty());
573
574        assert_eq!(seq_b.len(), 5);
575        assert_eq!(&seq_b[0], b"123");
576        assert_eq!(&seq_b[1], b"45");
577        assert_eq!(&seq_b[2], b"6");
578        assert_eq!(&seq_b[3], b"7");
579        assert_eq!(&seq_b[4], b"89");
580
581        seq_b.retain(|b| b.len() >= 2);
582
583        assert_eq!(seq_b.len(), 3);
584        assert_eq!(&seq_b[0], b"123");
585        assert_eq!(&seq_b[1], b"45");
586        assert_eq!(&seq_b[2], b"89");
587
588        seq_b.retain(|b| b.len() <= 2);
589
590        assert_eq!(seq_b.len(), 2);
591        assert_eq!(&seq_b[0], b"45");
592        assert_eq!(&seq_b[1], b"89");
593
594        seq_b.push(b"123");
595
596        assert_eq!(seq_b.len(), 3);
597        assert_eq!(&seq_b[0], b"45");
598        assert_eq!(&seq_b[1], b"89");
599        assert_eq!(&seq_b[2], b"123");
600
601        seq_b.retain(|b| b.len() >= 3);
602
603        assert_eq!(seq_b.len(), 1);
604        assert_eq!(&seq_b[0], b"123");
605
606        seq_b.resize(3);
607
608        assert_eq!(seq_b.len(), 3);
609        assert_eq!(&seq_b[0], b"123");
610        assert_eq!(&seq_b[1], b"");
611        assert_eq!(&seq_b[2], b"");
612
613        seq_b.truncate(5);
614
615        assert_eq!(seq_b.len(), 3);
616        assert_eq!(&seq_b[0], b"123");
617        assert_eq!(&seq_b[1], b"");
618        assert_eq!(&seq_b[2], b"");
619
620        seq_b.truncate(2);
621
622        assert_eq!(seq_b.len(), 2);
623        assert_eq!(&seq_b[0], b"123");
624        assert_eq!(&seq_b[1], b"");
625    }
626}