| 1 | use crate::utils::ring_buffer_ranges; |
| 2 | use core::{mem::MaybeUninit, num::NonZeroUsize, ops::Range, ptr}; |
| 3 | |
| 4 | /// Basic ring buffer functionality. |
| 5 | /// |
| 6 | /// Provides an access to raw underlying memory and `head`/`tail` counters. |
| 7 | /// |
| 8 | /// *It is recommended not to use this trait directly. Use [`Producer`](`crate::Producer`) and [`Consumer`](`crate::Consumer`) instead.* |
| 9 | /// |
| 10 | /// # Details |
| 11 | /// |
| 12 | /// The ring buffer consists of an array (of `capacity` size) and two counters: `head` and `tail`. |
| 13 | /// When an item is extracted from the ring buffer it is taken from the `head` position and after that `head` is incremented. |
| 14 | /// New item is appended to the `tail` position and `tail` is incremented after that. |
| 15 | /// |
| 16 | /// The `head` and `tail` counters are modulo `2 * capacity` (not just `capacity`). |
| 17 | /// It allows us to distinguish situations when the buffer is empty (`head == tail`) and when the buffer is full (`tail - head` modulo `2 * capacity` equals to `capacity`) |
| 18 | /// without using the space for an extra element in container. |
| 19 | /// And obviously we cannot store more than `capacity` items in the buffer, so `tail - head` modulo `2 * capacity` is not allowed to be greater than `capacity`. |
| 20 | pub trait RbBase<T> { |
| 21 | /// Returns part of underlying raw ring buffer memory as slices. |
| 22 | /// |
| 23 | /// For more information see [`SharedStorage::as_mut_slices`](`crate::ring_buffer::storage::SharedStorage::as_mut_slices`). |
| 24 | /// |
| 25 | /// # Safety |
| 26 | /// |
| 27 | /// Only non-overlapping slices allowed to exist at the same time. |
| 28 | /// |
| 29 | /// Modifications of this data must properly update `head` and `tail` positions. |
| 30 | /// |
| 31 | /// *Accessing raw data is extremely unsafe.* |
| 32 | /// It is recommended to use [`Consumer::as_slices`](`crate::Consumer::as_slices`) and [`Producer::free_space_as_slices`](`crate::Producer::free_space_as_slices`) instead. |
| 33 | unsafe fn slices( |
| 34 | &self, |
| 35 | head: usize, |
| 36 | tail: usize, |
| 37 | ) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]); |
| 38 | |
| 39 | /// Capacity of the ring buffer. |
| 40 | /// |
| 41 | /// It is constant during the whole ring buffer lifetime. |
| 42 | fn capacity_nonzero(&self) -> NonZeroUsize; |
| 43 | |
| 44 | /// Head position. |
| 45 | fn head(&self) -> usize; |
| 46 | |
| 47 | /// Tail position. |
| 48 | fn tail(&self) -> usize; |
| 49 | |
| 50 | /// Modulus for `head` and `tail` values. |
| 51 | /// |
| 52 | /// Equals to `2 * len`. |
| 53 | #[inline ] |
| 54 | fn modulus(&self) -> NonZeroUsize { |
| 55 | unsafe { NonZeroUsize::new_unchecked(2 * self.capacity_nonzero().get()) } |
| 56 | } |
| 57 | |
| 58 | /// The number of items stored in the buffer at the moment. |
| 59 | fn occupied_len(&self) -> usize { |
| 60 | let modulus = self.modulus(); |
| 61 | (modulus.get() + self.tail() - self.head()) % modulus |
| 62 | } |
| 63 | |
| 64 | /// The number of vacant places in the buffer at the moment. |
| 65 | fn vacant_len(&self) -> usize { |
| 66 | let modulus = self.modulus(); |
| 67 | (self.capacity_nonzero().get() + self.head() - self.tail()) % modulus |
| 68 | } |
| 69 | |
| 70 | /// Checks if the occupied range is empty. |
| 71 | fn is_empty(&self) -> bool { |
| 72 | self.head() == self.tail() |
| 73 | } |
| 74 | |
| 75 | /// Checks if the vacant range is empty. |
| 76 | fn is_full(&self) -> bool { |
| 77 | self.vacant_len() == 0 |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | /// Ring buffer read end. |
| 82 | /// |
| 83 | /// Provides access to occupied memory and mechanism of item extraction. |
| 84 | /// |
| 85 | /// *It is recommended not to use this trait directly. Use [`Producer`](`crate::Producer`) and [`Consumer`](`crate::Consumer`) instead.* |
| 86 | pub trait RbRead<T>: RbBase<T> { |
| 87 | /// Sets the new **head** position. |
| 88 | /// |
| 89 | /// # Safety |
| 90 | /// |
| 91 | /// This call must cohere with ring buffer data modification. |
| 92 | /// |
| 93 | /// It is recommended to use `Self::advance_head` instead. |
| 94 | unsafe fn set_head(&self, value: usize); |
| 95 | |
| 96 | /// Move **head** position by `count` items forward. |
| 97 | /// |
| 98 | /// # Safety |
| 99 | /// |
| 100 | /// First `count` items in occupied area must be **initialized** before this call. |
| 101 | /// |
| 102 | /// *In debug mode panics if `count` is greater than number of items in the ring buffer.* |
| 103 | unsafe fn advance_head(&self, count: usize) { |
| 104 | debug_assert!(count <= self.occupied_len()); |
| 105 | self.set_head((self.head() + count) % self.modulus()); |
| 106 | } |
| 107 | |
| 108 | /// Returns a pair of ranges of [`Self::occupied_slices`] location in underlying container. |
| 109 | #[inline ] |
| 110 | fn occupied_ranges(&self) -> (Range<usize>, Range<usize>) { |
| 111 | ring_buffer_ranges(self.capacity_nonzero(), self.head(), self.tail()) |
| 112 | } |
| 113 | |
| 114 | /// Provides a direct mutable access to the ring buffer occupied memory. |
| 115 | /// |
| 116 | /// Returns a pair of slices of stored items, the second one may be empty. |
| 117 | /// Elements with lower indices in slice are older. First slice contains older items that second one. |
| 118 | /// |
| 119 | /// # Safety |
| 120 | /// |
| 121 | /// All items are initialized. Elements must be removed starting from the beginning of first slice. |
| 122 | /// When all items are removed from the first slice then items must be removed from the beginning of the second slice. |
| 123 | /// |
| 124 | /// *This method must be followed by [`Self::advance_head`] call with the number of items being removed previously as argument.* |
| 125 | /// *No other mutating calls allowed before that.* |
| 126 | #[inline ] |
| 127 | unsafe fn occupied_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) { |
| 128 | self.slices(self.head(), self.tail()) |
| 129 | } |
| 130 | |
| 131 | /// Removes items from the head of ring buffer and drops them. |
| 132 | /// |
| 133 | /// + If `count_or_all` is `Some(count)` then exactly `count` items will be removed. |
| 134 | /// *In debug mode panics if `count` is greater than number of items stored in the buffer.* |
| 135 | /// + If `count_or_all` is `None` then all items in ring buffer will be removed. |
| 136 | /// *If there is concurring producer activity then the buffer may be not empty after this call.* |
| 137 | /// |
| 138 | /// Returns the number of removed items. |
| 139 | /// |
| 140 | /// # Safety |
| 141 | /// |
| 142 | /// Must not be called concurrently. |
| 143 | unsafe fn skip_internal(&self, count_or_all: Option<usize>) -> usize { |
| 144 | let (left, right) = self.occupied_slices(); |
| 145 | let count = match count_or_all { |
| 146 | Some(count) => { |
| 147 | debug_assert!(count <= left.len() + right.len()); |
| 148 | count |
| 149 | } |
| 150 | None => left.len() + right.len(), |
| 151 | }; |
| 152 | for elem in left.iter_mut().chain(right.iter_mut()).take(count) { |
| 153 | ptr::drop_in_place(elem.as_mut_ptr()); |
| 154 | } |
| 155 | self.advance_head(count); |
| 156 | count |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | /// Ring buffer write end. |
| 161 | /// |
| 162 | /// Provides access to vacant memory and mechanism of item insertion. |
| 163 | /// |
| 164 | /// *It is recommended not to use this trait directly. Use [`Producer`](`crate::Producer`) and [`Consumer`](`crate::Consumer`) instead.* |
| 165 | pub trait RbWrite<T>: RbBase<T> { |
| 166 | /// Sets the new **tail** position. |
| 167 | /// |
| 168 | /// # Safety |
| 169 | /// |
| 170 | /// This call must cohere with ring buffer data modification. |
| 171 | /// |
| 172 | /// It is recommended to use `Self::advance_tail` instead. |
| 173 | unsafe fn set_tail(&self, value: usize); |
| 174 | |
| 175 | /// Move **tail** position by `count` items forward. |
| 176 | /// |
| 177 | /// # Safety |
| 178 | /// |
| 179 | /// First `count` items in vacant area must be **de-initialized** (dropped) before this call. |
| 180 | /// |
| 181 | /// *In debug mode panics if `count` is greater than number of vacant places in the ring buffer.* |
| 182 | unsafe fn advance_tail(&self, count: usize) { |
| 183 | debug_assert!(count <= self.vacant_len()); |
| 184 | self.set_tail((self.tail() + count) % self.modulus()); |
| 185 | } |
| 186 | |
| 187 | /// Returns a pair of ranges of [`Self::vacant_slices`] location in underlying container. |
| 188 | #[inline ] |
| 189 | fn vacant_ranges(&self) -> (Range<usize>, Range<usize>) { |
| 190 | ring_buffer_ranges( |
| 191 | self.capacity_nonzero(), |
| 192 | self.tail(), |
| 193 | self.head() + self.capacity_nonzero().get(), |
| 194 | ) |
| 195 | } |
| 196 | |
| 197 | /// Provides a direct access to the ring buffer vacant memory. |
| 198 | /// Returns a pair of slices of uninitialized memory, the second one may be empty. |
| 199 | /// |
| 200 | /// # Safety |
| 201 | /// |
| 202 | /// Vacant memory is uninitialized. Initialized items must be put starting from the beginning of first slice. |
| 203 | /// When first slice is fully filled then items must be put to the beginning of the second slice. |
| 204 | /// |
| 205 | /// *This method must be followed by [`Self::advance_tail`] call with the number of items being put previously as argument.* |
| 206 | /// *No other mutating calls allowed before that.* |
| 207 | #[inline ] |
| 208 | unsafe fn vacant_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) { |
| 209 | self.slices(self.tail(), self.head() + self.capacity_nonzero().get()) |
| 210 | } |
| 211 | } |
| 212 | |