1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use core::mem;

use crate::common::segment_iterator::SegmentIterator;
use crate::Segment;

/// It's an implementation of `SegmentIterator` that does not heap-allocate. Alternatives are
/// `BinBuilder` and `StrBuilder`; `SegmentsSlice` is less flexible but cheaper
/// (smaller stack; faster).
///
/// ```rust
/// use abin::{BinSegment, SegmentsSlice, Bin, NewBin, BinFactory, AnyBin};
///
/// let segments = &mut [BinSegment::Static("Hello, ".as_bytes()),
///     BinSegment::Static("World!".as_bytes())];
/// let iterator = SegmentsSlice::new(segments);
/// let bin : Bin = NewBin::from_segments(iterator);
/// assert_eq!("Hello, World!".as_bytes(), bin.as_slice());
/// ```
pub struct SegmentsSlice<'a, TSegment> {
    slice: &'a mut [TSegment],
    number_of_bytes: usize,
    pos: usize,
    /// this is set to the index of the single item (if there's just one single item).
    single_index: Option<usize>,
}

impl<'a, TSegment> SegmentsSlice<'a, TSegment>
where
    TSegment: Segment,
{
    /// Important: The given slice might be modified; do not use this slice.
    #[inline]
    pub fn new(slice: &'a mut [TSegment]) -> Self {
        // analyze content.
        let mut number_of_bytes = 0;
        let mut no_item_yet = true;
        let mut single_index = None;
        for (index, item) in slice.iter().enumerate() {
            let item_len = item.number_of_bytes();
            // ignore all empty items
            if item_len > 0 {
                number_of_bytes += item_len;
                if no_item_yet {
                    single_index = Some(index);
                    no_item_yet = false;
                } else {
                    // more than one
                    single_index = None;
                }
            }
        }

        Self {
            slice,
            number_of_bytes,
            pos: 0,
            single_index,
        }
    }

    #[inline]
    fn remaining(&self) -> usize {
        let len = self.slice.len();
        if self.pos < len {
            len - self.pos
        } else {
            0
        }
    }

    fn take(&mut self, index: usize) -> Option<TSegment> {
        if index < self.slice.len() {
            let empty = TSegment::empty();
            Some(mem::replace(&mut self.slice[index], empty))
        } else {
            None
        }
    }
}

impl<'a, TSegment> SegmentIterator<TSegment> for SegmentsSlice<'a, TSegment>
where
    TSegment: Segment,
{
    fn exact_number_of_bytes(&self) -> Option<usize> {
        Some(self.number_of_bytes)
    }

    fn is_empty(&self) -> bool {
        self.number_of_bytes == 0
    }

    fn single(mut self) -> Result<TSegment, Self>
    where
        Self: Sized,
    {
        if let Some(single_index) = self.single_index {
            let taken = SegmentsSlice::take(&mut self, single_index);
            Ok(taken.expect("Implementation error (single_index is invalid)"))
        } else {
            Err(self)
        }
    }
}

impl<'a, TSegment: Segment> Iterator for SegmentsSlice<'a, TSegment> {
    type Item = TSegment;

    fn next(&mut self) -> Option<Self::Item> {
        let item = SegmentsSlice::take(self, self.pos);
        self.pos += 1;
        item
    }
}

impl<'a, TSegment: Segment> ExactSizeIterator for SegmentsSlice<'a, TSegment> {
    #[inline]
    fn len(&self) -> usize {
        self.remaining()
    }
}