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 smallvec::{smallvec, SmallVec};
use std::ops::{Deref, DerefMut};

use super::PollState;

/// The maximum number of entries that `PollStates` can store without
/// dynamic memory allocation.
///
/// The heap variant is the minimum size the data structure can have.
/// It consists of a boxed slice (=2 usizes) and space for the enum
/// tag (another usize because of padding), so 3 usizes.
/// The inline variant then consists of `3 * size_of(usize) - 2` entries.
/// Each entry is a byte and we subtract one byte for a length field,
/// and another byte for the enum tag.
///
/// ```txt
///                                 Boxed
///                                 vvvvv
/// tag
///  | <-------padding----> <--- Box<[T]>::len ---> <--- Box<[T]>::ptr --->
/// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23  <bytes
///  |  | <------------------- entries ----------------------------------->
/// tag |
///    len                          ^^^^^
///                                 Inline
/// ```
const MAX_INLINE_ENTRIES: usize = std::mem::size_of::<usize>() * 3 - 2;

#[derive(Default)]
pub(crate) struct PollVec(SmallVec<[PollState; MAX_INLINE_ENTRIES]>);

impl PollVec {
    pub(crate) fn new(len: usize) -> Self {
        Self(smallvec![PollState::None; len])
    }

    pub(crate) fn new_pending(len: usize) -> Self {
        Self(smallvec![PollState::Pending; len])
    }

    /// Get an iterator of indexes of all items which are "ready".
    pub(crate) fn ready_indexes(&self) -> impl Iterator<Item = usize> + '_ {
        self.iter()
            .cloned()
            .enumerate()
            .filter(|(_, state)| state.is_ready())
            .map(|(i, _)| i)
    }

    /// Get an iterator of indexes of all items which are "pending".
    #[allow(unused)]
    pub(crate) fn pending_indexes(&self) -> impl Iterator<Item = usize> + '_ {
        self.iter()
            .cloned()
            .enumerate()
            .filter(|(_, state)| state.is_pending())
            .map(|(i, _)| i)
    }

    /// Get an iterator of indexes of all items which are "consumed".
    #[allow(unused)]
    pub(crate) fn consumed_indexes(&self) -> impl Iterator<Item = usize> + '_ {
        self.iter()
            .cloned()
            .enumerate()
            .filter(|(_, state)| state.is_none())
            .map(|(i, _)| i)
    }

    /// Mark all items as "pending"
    #[inline]
    pub(crate) fn set_all_pending(&mut self) {
        self.0.fill(PollState::Pending);
    }

    /// Mark all items as "none"
    #[inline]
    #[allow(unused)]
    pub(crate) fn set_all_none(&mut self) {
        self.0.fill(PollState::None);
    }

    /// Resize the `PollVec`
    pub(crate) fn resize(&mut self, len: usize) {
        self.0.resize_with(len, || PollState::None)
    }
}

impl Deref for PollVec {
    type Target = [PollState];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for PollVec {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

#[cfg(test)]
mod tests {
    use super::{PollVec, MAX_INLINE_ENTRIES};

    #[test]
    fn type_size() {
        // PollVec is three words plus two bits
        assert_eq!(
            std::mem::size_of::<PollVec>(),
            std::mem::size_of::<usize>() * 4
        );
    }

    #[test]
    fn boxed_does_not_allocate_twice() {
        // Make sure the debug_assertions in PollStates::new() don't fail.
        let _ = PollVec::new_pending(MAX_INLINE_ENTRIES + 10);
    }
}