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}