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 | |