compact_strings/
compact_bytestrings.rs

1use core::{fmt::Debug, ops::Index};
2
3use alloc::vec::Vec;
4
5use crate::{metadata::Metadata, CompactStrings};
6
7/// A more compact but limited representation of a list of bytestrings.
8///
9/// Strings are stored contiguously in a vector of bytes, with their lengths and starting indices
10/// being stored separately.
11///
12/// Limitations include being unable to mutate bytestrings stored in the vector.
13///
14/// # Examples
15/// ```
16/// # use compact_strings::CompactBytestrings;
17/// let mut cmpbytes = CompactBytestrings::with_capacity(20, 3);
18///
19/// cmpbytes.push(b"One");
20/// cmpbytes.push(b"Two");
21/// cmpbytes.push(b"Three");
22///
23/// cmpbytes.remove(1);
24///
25/// assert_eq!(cmpbytes.get(0), Some(b"One".as_slice()));
26/// assert_eq!(cmpbytes.get(1), Some(b"Three".as_slice()));
27/// assert_eq!(cmpbytes.get(2), None);
28/// ```
29pub struct CompactBytestrings {
30    pub(crate) data: Vec<u8>,
31    pub(crate) meta: Vec<Metadata>,
32}
33
34impl CompactBytestrings {
35    /// Constructs a new, empty [`CompactBytestrings`].
36    ///
37    /// The [`CompactBytestrings`] will not allocate until bytestrings are pushed into it.
38    ///
39    /// # Examples
40    /// ```
41    /// # use compact_strings::CompactBytestrings;
42    /// let mut cmpbytes = CompactBytestrings::new();
43    /// ```
44    #[must_use]
45    pub const fn new() -> Self {
46        Self {
47            data: Vec::new(),
48            meta: Vec::new(),
49        }
50    }
51
52    /// Constructs a new, empty [`CompactBytestrings`] with at least the specified capacities in each
53    /// vector.
54    ///
55    /// - `data_capacity`: The capacity of the data vector where the bytes of the bytestrings are stored.
56    /// - `capacity_meta`: The capacity of the meta vector where the starting indices and lengths
57    /// of the bytestrings are stored.
58    ///
59    /// The [`CompactBytestrings`] will be able to hold at least *`data_capacity`* bytes worth of bytestrings
60    /// without reallocating the data vector, and at least *`capacity_meta`* of starting indices and
61    /// lengths without reallocating the meta vector. This method is allowed to allocate for more bytes
62    /// than the capacities. If a capacity is 0, the vector will not allocate.
63    ///
64    /// It is important to note that although the data and meta vectors have the
65    /// minimum capacities specified, they will have a zero *length*.
66    ///
67    /// If it is important to know the exact allocated capacity of the data vector, always use the
68    /// [`capacity`] method after construction.
69    ///
70    /// [`capacity`]: CompactBytestrings::capacity
71    ///
72    /// # Examples
73    /// ```
74    /// # use compact_strings::CompactBytestrings;
75    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 3);
76    ///
77    /// assert_eq!(cmpbytes.len(), 0);
78    /// assert!(cmpbytes.capacity() >= 20);
79    /// assert!(cmpbytes.capacity_meta() >= 3);
80    /// ```
81    #[must_use]
82    pub fn with_capacity(data_capacity: usize, capacity_meta: usize) -> Self {
83        Self {
84            data: Vec::with_capacity(data_capacity),
85            meta: Vec::with_capacity(capacity_meta),
86        }
87    }
88
89    /// Appends a bytestring to the back of the [`CompactBytestrings`].
90    ///
91    /// # Examples
92    /// ```
93    /// # use compact_strings::CompactBytestrings;
94    /// let mut cmpbytes = CompactBytestrings::new();
95    /// cmpbytes.push(b"One");
96    /// cmpbytes.push(b"Two");
97    /// cmpbytes.push(b"Three");
98    ///
99    /// assert_eq!(cmpbytes.get(0), Some(b"One".as_slice()));
100    /// assert_eq!(cmpbytes.get(1), Some(b"Two".as_slice()));
101    /// assert_eq!(cmpbytes.get(2), Some(b"Three".as_slice()));
102    /// assert_eq!(cmpbytes.get(3), None);
103    /// ```
104    pub fn push<S>(&mut self, bytestring: S)
105    where
106        S: AsRef<[u8]>,
107    {
108        let bytestr = bytestring.as_ref();
109        self.meta
110            .push(Metadata::new(self.data.len(), bytestr.len()));
111        self.data.extend_from_slice(bytestr);
112    }
113
114    /// Returns a reference to the bytestring stored in the [`CompactBytestrings`] at that position.
115    ///
116    /// # Examples
117    /// ```
118    /// # use compact_strings::CompactBytestrings;
119    /// let mut cmpbytes = CompactBytestrings::new();
120    /// cmpbytes.push(b"One");
121    /// cmpbytes.push(b"Two");
122    /// cmpbytes.push(b"Three");
123    ///
124    /// assert_eq!(cmpbytes.get(0), Some(b"One".as_slice()));
125    /// assert_eq!(cmpbytes.get(1), Some(b"Two".as_slice()));
126    /// assert_eq!(cmpbytes.get(2), Some(b"Three".as_slice()));
127    /// assert_eq!(cmpbytes.get(3), None);
128    /// ```
129    #[must_use]
130    pub fn get(&self, index: usize) -> Option<&[u8]> {
131        let (start, len) = self.meta.get(index)?.as_tuple();
132        if cfg!(feature = "no_unsafe") {
133            self.data.get(start..start + len)
134        } else {
135            unsafe { Some(self.data.get_unchecked(start..start + len)) }
136        }
137    }
138
139    /// Returns a reference to the bytestring stored in the [`CompactBytestrings`] at that position, without
140    /// doing bounds checking.
141    ///
142    /// # Safety
143    /// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used.
144    ///
145    /// # Examples
146    /// ```
147    /// # use compact_strings::CompactBytestrings;
148    /// let mut cmpbytes = CompactBytestrings::new();
149    /// cmpbytes.push(b"One");
150    /// cmpbytes.push(b"Two");
151    /// cmpbytes.push(b"Three");
152    ///
153    /// unsafe {
154    ///     assert_eq!(cmpbytes.get_unchecked(0), b"One".as_slice());
155    ///     assert_eq!(cmpbytes.get_unchecked(1), b"Two".as_slice());
156    ///     assert_eq!(cmpbytes.get_unchecked(2), b"Three".as_slice());
157    /// }
158    /// ```
159    #[must_use]
160    #[cfg(not(feature = "no_unsafe"))]
161    pub unsafe fn get_unchecked(&self, index: usize) -> &[u8] {
162        let (start, len) = self.meta.get_unchecked(index).as_tuple();
163        self.data.get_unchecked(start..start + len)
164    }
165
166    /// Returns the number of bytestrings in the [`CompactBytestrings`], also referred to as its 'length'.
167    ///
168    /// # Examples
169    /// ```
170    /// # use compact_strings::CompactBytestrings;
171    /// let mut cmpbytes = CompactBytestrings::new();
172    ///
173    /// cmpbytes.push(b"One");
174    /// cmpbytes.push(b"Two");
175    /// cmpbytes.push(b"Three");
176    ///
177    /// assert_eq!(cmpbytes.len(), 3);
178    /// ```
179    #[inline]
180    #[must_use]
181    pub fn len(&self) -> usize {
182        self.meta.len()
183    }
184
185    /// Returns true if the [`CompactBytestrings`] contains no bytestrings.
186    ///
187    /// # Examples
188    /// ```
189    /// # use compact_strings::CompactBytestrings;
190    /// let mut cmpbytes = CompactBytestrings::new();
191    /// assert!(cmpbytes.is_empty());
192    ///
193    /// cmpbytes.push(b"One");
194    ///
195    /// assert!(!cmpbytes.is_empty());
196    /// ```
197    #[inline]
198    #[must_use]
199    pub fn is_empty(&self) -> bool {
200        self.len() == 0
201    }
202
203    /// Returns the number of bytes the data vector can store without reallocating.
204    ///
205    /// # Examples
206    /// ```
207    /// # use compact_strings::CompactBytestrings;
208    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 3);
209    ///
210    /// cmpbytes.push(b"One");
211    ///
212    /// assert!(cmpbytes.capacity() >= 20);
213    /// ```
214    #[inline]
215    #[must_use]
216    pub fn capacity(&self) -> usize {
217        self.data.capacity()
218    }
219
220    /// Returns the number of starting indices and lengths can store without reallocating.
221    ///
222    /// # Examples
223    /// ```
224    /// # use compact_strings::CompactBytestrings;
225    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 3);
226    ///
227    /// cmpbytes.push(b"One");
228    /// cmpbytes.push(b"Two");
229    /// cmpbytes.push(b"Three");
230    /// assert!(cmpbytes.capacity_meta() >= 3);
231    ///
232    /// cmpbytes.push(b"Three");
233    /// assert!(cmpbytes.capacity_meta() > 3);
234    /// ```
235    #[inline]
236    #[must_use]
237    pub fn capacity_meta(&self) -> usize {
238        self.meta.capacity()
239    }
240
241    /// Clears the [`CompactBytestrings`], removing all bytestrings.
242    ///
243    /// Note that this method has no effect on the allocated capacity of the vectors.
244    ///
245    /// # Examples
246    /// ```
247    /// # use compact_strings::CompactBytestrings;
248    /// let mut cmpbytes = CompactBytestrings::new();
249    ///
250    /// cmpbytes.push(b"One");
251    /// cmpbytes.push(b"Two");
252    /// cmpbytes.push(b"Three");
253    /// cmpbytes.clear();
254    ///
255    /// assert!(cmpbytes.is_empty());
256    /// ```
257    pub fn clear(&mut self) {
258        self.data.clear();
259        self.meta.clear();
260    }
261
262    /// Shrinks the capacity of the data vector, which stores the bytes of the held bytestrings, as much as possible.
263    ///
264    /// It will drop down as close as possible to the length but the allocator
265    /// may still inform the vector that there is space for a few more elements.
266    ///
267    /// # Examples
268    /// ```
269    /// # use compact_strings::CompactBytestrings;
270    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 3);
271    ///
272    /// cmpbytes.push(b"One");
273    /// cmpbytes.push(b"Two");
274    /// cmpbytes.push(b"Three");
275    ///
276    /// assert!(cmpbytes.capacity() >= 20);
277    /// cmpbytes.shrink_to_fit();
278    /// assert!(cmpbytes.capacity() >= 3);
279    /// ```
280    #[inline]
281    pub fn shrink_to_fit(&mut self) {
282        self.data.shrink_to_fit();
283    }
284
285    /// Shrinks the capacity of the info vector, which stores the starting indices and lengths of
286    /// the held bytestrings, as much as possible.
287    ///
288    /// It will drop down as close as possible to the length but the allocator
289    /// may still inform the vector that there is space for a few more elements.
290    ///
291    /// # Examples
292    /// ```
293    /// # use compact_strings::CompactBytestrings;
294    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 10);
295    ///
296    /// cmpbytes.push(b"One");
297    /// cmpbytes.push(b"Two");
298    /// cmpbytes.push(b"Three");
299    ///
300    /// assert!(cmpbytes.capacity_meta() >= 10);
301    /// cmpbytes.shrink_to_fit();
302    /// assert!(cmpbytes.capacity_meta() >= 3);
303    /// ```
304    #[inline]
305    pub fn shrink_meta_to_fit(&mut self) {
306        self.meta.shrink_to_fit();
307    }
308
309    /// Shrinks the capacity of the data vector, which stores the bytes of the held bytestrings, with a lower bound.
310    ///
311    /// The capacity will remain at least as large as both the length and the supplied value.
312    ///
313    /// If the current capacity is less than the lower limit, this is a no-op.
314    ///
315    /// # Examples
316    /// ```
317    /// # use compact_strings::CompactBytestrings;
318    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 4);
319    ///
320    /// cmpbytes.push(b"One");
321    /// cmpbytes.push(b"Two");
322    /// cmpbytes.push(b"Three");
323    ///
324    /// assert!(cmpbytes.capacity() >= 20);
325    /// cmpbytes.shrink_to(4);
326    /// assert!(cmpbytes.capacity() >= 4);
327    /// ```
328    #[inline]
329    pub fn shrink_to(&mut self, min_capacity: usize) {
330        self.data.shrink_to(min_capacity);
331    }
332
333    /// Shrinks the capacity of the meta vector, which starting indices and lengths of the held bytestrings,
334    /// with a lower bound.
335    ///
336    /// The capacity will remain at least as large as both the length and the supplied value.
337    ///
338    /// If the current capacity is less than the lower limit, this is a no-op.
339    ///
340    /// # Examples
341    /// ```
342    /// # use compact_strings::CompactBytestrings;
343    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 10);
344    ///
345    /// cmpbytes.push(b"One");
346    /// cmpbytes.push(b"Two");
347    /// cmpbytes.push(b"Three");
348    ///
349    /// assert!(cmpbytes.capacity_meta() >= 10);
350    /// cmpbytes.shrink_meta_to(4);
351    /// assert!(cmpbytes.capacity_meta() >= 4);
352    /// ```
353    #[inline]
354    pub fn shrink_meta_to(&mut self, min_capacity: usize) {
355        self.meta.shrink_to(min_capacity);
356    }
357
358    /// Removes the data pointing to where the bytestring at the specified index is stored.
359    ///
360    /// Note: This does not remove the bytes of the bytestring from memory, you may want to use
361    /// [`remove`] if you desire that behavior.
362    ///
363    /// Note: Because this shifts over the remaining elements in the meta vector, it has a
364    /// worst-case performance of *O*(*n*).
365    ///
366    /// [`remove`]: CompactBytestrings::remove
367    ///
368    /// # Examples
369    /// ```
370    /// # use compact_strings::CompactBytestrings;
371    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 3);
372    ///
373    /// cmpbytes.push(b"One");
374    /// cmpbytes.push(b"Two");
375    /// cmpbytes.push(b"Three");
376    ///
377    /// cmpbytes.ignore(1);
378    ///
379    /// assert_eq!(cmpbytes.get(0), Some(b"One".as_slice()));
380    /// assert_eq!(cmpbytes.get(1), Some(b"Three".as_slice()));
381    /// assert_eq!(cmpbytes.get(2), None);
382    /// ```
383    #[track_caller]
384    pub fn ignore(&mut self, index: usize) {
385        #[cold]
386        #[inline(never)]
387        #[track_caller]
388        fn assert_failed(index: usize, len: usize) -> ! {
389            panic!("removal index (is {index}) should be < len (is {len})");
390        }
391
392        let len = self.len();
393        if index >= len {
394            assert_failed(index, len);
395        }
396
397        self.meta.remove(index);
398    }
399
400    /// Removes the bytes of the bytestring and data pointing to the bytestring is stored.
401    ///
402    /// Note: This does not shrink the vectors where the bytes of the bytestring and data to the bytestring
403    /// are stored. You may shrink the data vector with [`shrink_to`] and [`shrink_to_fit`] and the
404    /// meta vector with [`shrink_meta_to`] and [`shrink_meta_to_fit`].
405    ///
406    /// Note: Because this shifts over the remaining elements in both data and meta vectors, it
407    /// has a worst-case performance of *O*(*n*). If you don't need the bytes of the bytestring to
408    /// be removed, use [`ignore`] instead.
409    ///
410    /// [`shrink_to`]: CompactBytestrings::shrink_to
411    /// [`shrink_to_fit`]: CompactBytestrings::shrink_to_fit
412    /// [`shrink_meta_to`]: CompactBytestrings::shrink_meta_to
413    /// [`shrink_meta_to_fit`]: CompactBytestrings::shrink_meta_to_fit
414    /// [`ignore`]: CompactBytestrings::ignore
415    ///
416    /// # Examples
417    /// ```
418    /// # use compact_strings::CompactBytestrings;
419    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 3);
420    ///
421    /// cmpbytes.push(b"One");
422    /// cmpbytes.push(b"Two");
423    /// cmpbytes.push(b"Three");
424    ///
425    /// cmpbytes.remove(1);
426    ///
427    /// assert_eq!(cmpbytes.get(0), Some(b"One".as_slice()));
428    /// assert_eq!(cmpbytes.get(1), Some(b"Three".as_slice()));
429    /// assert_eq!(cmpbytes.get(2), None);
430    /// ```
431    #[track_caller]
432    pub fn remove(&mut self, index: usize) {
433        #[cold]
434        #[inline(never)]
435        #[track_caller]
436        fn assert_failed(index: usize, len: usize) -> ! {
437            panic!("removal index (is {index}) should be < len (is {len})");
438        }
439
440        let len = self.len();
441        if index >= len {
442            assert_failed(index, len);
443        }
444
445        let (start, len) = self.meta.remove(index).as_tuple();
446        let inner_len = self.data.len();
447
448        for meta in self.meta.iter_mut().skip(index) {
449            meta.start -= start;
450        }
451
452        if cfg!(feature = "no_unsafe") {
453            self.data.copy_within(start + len..inner_len, start);
454        } else {
455            unsafe {
456                let ptr = self.data.as_mut_ptr().add(start);
457
458                core::ptr::copy(ptr.add(len), ptr, inner_len - start - len);
459
460                self.data.set_len(inner_len - len);
461            }
462        }
463    }
464
465    /// Returns an iterator over the slice.
466    ///
467    /// The iterator yields all items from start to end.
468    ///
469    /// # Examples
470    ///
471    /// ```
472    /// # use compact_strings::CompactBytestrings;
473    /// let mut cmpbytes = CompactBytestrings::with_capacity(20, 3);
474    /// cmpbytes.push(b"One");
475    /// cmpbytes.push(b"Two");
476    /// cmpbytes.push(b"Three");
477    /// let mut iterator = cmpbytes.iter();
478    ///
479    /// assert_eq!(iterator.next(), Some(b"One".as_slice()));
480    /// assert_eq!(iterator.next(), Some(b"Two".as_slice()));
481    /// assert_eq!(iterator.next(), Some(b"Three".as_slice()));
482    /// assert_eq!(iterator.next(), None);
483    /// ```
484    #[inline]
485    pub fn iter(&self) -> Iter<'_> {
486        Iter::new(self)
487    }
488}
489
490impl Clone for CompactBytestrings {
491    fn clone(&self) -> Self {
492        let mut data = Vec::with_capacity(self.meta.iter().map(|m| m.len).sum());
493        let mut meta = Vec::with_capacity(self.meta.len());
494
495        for bytes in self {
496            meta.push(Metadata {
497                start: data.len(),
498                len: bytes.len(),
499            });
500            data.extend_from_slice(bytes);
501        }
502
503        Self { data, meta }
504    }
505}
506
507impl PartialEq for CompactBytestrings {
508    fn eq(&self, other: &Self) -> bool {
509        let len = self.len();
510        if len != other.len() {
511            return false;
512        }
513
514        for idx in 0..len {
515            if self[idx] != other[idx] {
516                return false;
517            }
518        }
519
520        true
521    }
522}
523
524impl Debug for CompactBytestrings {
525    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
526        f.debug_list().entries(self.iter()).finish()
527    }
528}
529
530impl<S> Extend<S> for CompactBytestrings
531where
532    S: AsRef<[u8]>,
533{
534    #[inline]
535    fn extend<I: IntoIterator<Item = S>>(&mut self, iter: I) {
536        for s in iter {
537            self.push(&s);
538        }
539    }
540}
541
542impl Index<usize> for CompactBytestrings {
543    type Output = [u8];
544
545    #[inline]
546    fn index(&self, index: usize) -> &Self::Output {
547        self.get(index).unwrap()
548    }
549}
550
551/// Iterator over bytestrings in a [`CompactBytestrings`]
552///
553/// # Examples
554/// ```
555/// # use compact_strings::CompactBytestrings;
556/// let mut cmpbytes = CompactBytestrings::new();
557/// cmpbytes.push(b"One");
558/// cmpbytes.push(b"Two");
559/// cmpbytes.push(b"Three");
560///
561/// let mut iter = cmpbytes.into_iter();
562/// assert_eq!(iter.next(), Some(b"One".as_slice()));
563/// assert_eq!(iter.next(), Some(b"Two".as_slice()));
564/// assert_eq!(iter.next(), Some(b"Three".as_slice()));
565/// assert_eq!(iter.next(), None);
566/// ```
567#[must_use = "Iterators are lazy and do nothing unless consumed"]
568pub struct Iter<'a> {
569    data: &'a [u8],
570    iter: core::slice::Iter<'a, Metadata>,
571}
572
573impl<'a> Iter<'a> {
574    #[inline]
575    pub fn new(inner: &'a CompactBytestrings) -> Self {
576        Self {
577            data: &inner.data,
578            iter: inner.meta.iter(),
579        }
580    }
581}
582
583impl<'a> Iterator for Iter<'a> {
584    type Item = &'a [u8];
585
586    fn next(&mut self) -> Option<Self::Item> {
587        let (start, len) = self.iter.next()?.as_tuple();
588
589        if cfg!(feature = "no_unsafe") {
590            self.data.get(start..start + len)
591        } else {
592            unsafe { Some(self.data.get_unchecked(start..start + len)) }
593        }
594    }
595
596    fn nth(&mut self, n: usize) -> Option<Self::Item> {
597        let (start, len) = self.iter.nth(n)?.as_tuple();
598
599        if cfg!(feature = "no_unsafe") {
600            self.data.get(start..start + len)
601        } else {
602            unsafe { Some(self.data.get_unchecked(start..start + len)) }
603        }
604    }
605
606    #[inline]
607    fn count(self) -> usize
608    where
609        Self: Sized,
610    {
611        self.len()
612    }
613
614    #[inline]
615    fn last(mut self) -> Option<Self::Item>
616    where
617        Self: Sized,
618    {
619        self.next_back()
620    }
621
622    #[inline]
623    fn size_hint(&self) -> (usize, Option<usize>) {
624        self.iter.size_hint()
625    }
626}
627
628impl<'a> DoubleEndedIterator for Iter<'a> {
629    fn next_back(&mut self) -> Option<Self::Item> {
630        let (start, len) = self.iter.next_back()?.as_tuple();
631
632        if cfg!(feature = "no_unsafe") {
633            self.data.get(start..start + len)
634        } else {
635            unsafe { Some(self.data.get_unchecked(start..start + len)) }
636        }
637    }
638
639    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
640        let (start, len) = self.iter.nth_back(n)?.as_tuple();
641
642        if cfg!(feature = "no_unsafe") {
643            self.data.get(start..start + len)
644        } else {
645            unsafe { Some(self.data.get_unchecked(start..start + len)) }
646        }
647    }
648}
649
650impl ExactSizeIterator for Iter<'_> {
651    #[inline]
652    fn len(&self) -> usize {
653        self.iter.len()
654    }
655}
656
657impl<'a> IntoIterator for &'a CompactBytestrings {
658    type Item = &'a [u8];
659
660    type IntoIter = Iter<'a>;
661
662    #[inline]
663    fn into_iter(self) -> Self::IntoIter {
664        self.iter()
665    }
666}
667
668impl<S> FromIterator<S> for CompactBytestrings
669where
670    S: AsRef<[u8]>,
671{
672    fn from_iter<I: IntoIterator<Item = S>>(iter: I) -> Self {
673        let iter = iter.into_iter();
674        let meta_capacity = match iter.size_hint() {
675            (a, Some(b)) if a == b => a,
676            _ => 0,
677        };
678
679        let mut out = CompactBytestrings::with_capacity(0, meta_capacity);
680        for s in iter {
681            out.push(s);
682        }
683
684        out
685    }
686}
687
688impl<S, I> From<I> for CompactBytestrings
689where
690    S: AsRef<[u8]>,
691    I: IntoIterator<Item = S>,
692{
693    #[inline]
694    fn from(value: I) -> Self {
695        FromIterator::from_iter(value)
696    }
697}
698
699impl From<CompactStrings> for CompactBytestrings {
700    fn from(value: CompactStrings) -> Self {
701        value.0
702    }
703}
704
705#[cfg(test)]
706mod tests {
707    use crate::CompactBytestrings;
708
709    #[test]
710    fn exact_size_iterator() {
711        let mut cmpbytes = CompactBytestrings::new();
712
713        cmpbytes.push(b"One");
714        cmpbytes.push(b"Two");
715        cmpbytes.push(b"Three");
716
717        let mut iter = cmpbytes.iter();
718        assert_eq!(iter.len(), 3);
719        let _ = iter.next();
720        assert_eq!(iter.len(), 2);
721        let _ = iter.next();
722        assert_eq!(iter.len(), 1);
723        let _ = iter.next();
724        assert_eq!(iter.len(), 0);
725        let _ = iter.next();
726        assert_eq!(iter.len(), 0);
727    }
728
729    #[test]
730    fn double_ended_iterator() {
731        let mut cmpbytes = CompactBytestrings::new();
732
733        cmpbytes.push(b"One");
734        cmpbytes.push(b"Two");
735        cmpbytes.push(b"Three");
736        cmpbytes.push(b"Four");
737
738        let mut iter = cmpbytes.iter();
739        assert_eq!(iter.next(), Some(b"One".as_slice()));
740        assert_eq!(iter.next_back(), Some(b"Four".as_slice()));
741        assert_eq!(iter.next(), Some(b"Two".as_slice()));
742        assert_eq!(iter.next_back(), Some(b"Three".as_slice()));
743        assert_eq!(iter.next(), None);
744        assert_eq!(iter.next_back(), None);
745    }
746}