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