1 | use crate::utils::ring_buffer_ranges; |
2 | #[cfg (feature = "alloc" )] |
3 | use alloc::vec::Vec; |
4 | use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, num::NonZeroUsize, slice}; |
5 | |
6 | /// Abstract container for the ring buffer. |
7 | /// |
8 | /// Container items must be stored as a contiguous array. |
9 | /// |
10 | /// # Safety |
11 | /// |
12 | /// *[`Self::len`]/[`Self::is_empty`] must always return the same value.* |
13 | /// |
14 | /// *Container must not cause data race on concurrent [`Self::as_mut_slice`]/[`Self::as_mut_ptr`] calls.* |
15 | pub unsafe trait Container<T> { |
16 | /// Internal representation of the container. |
17 | /// |
18 | /// *Must not be aliased with its content.* |
19 | type Internal; |
20 | |
21 | /// Transform container to internal representation. |
22 | fn into_internal(self) -> Self::Internal; |
23 | /// Restore container from internal representation. |
24 | /// |
25 | /// # Safety |
26 | /// |
27 | /// `this` must be valid. |
28 | unsafe fn from_internal(this: Self::Internal) -> Self; |
29 | |
30 | /// Return pointer to the beginning of the container items. |
31 | fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T>; |
32 | /// Length of the container. |
33 | fn len(this: &Self::Internal) -> usize; |
34 | } |
35 | |
36 | unsafe impl<'a, T> Container<T> for &'a mut [MaybeUninit<T>] { |
37 | type Internal = (*mut MaybeUninit<T>, usize); |
38 | |
39 | fn into_internal(self) -> Self::Internal { |
40 | (self.as_mut_ptr(), self.len()) |
41 | } |
42 | unsafe fn from_internal(this: Self::Internal) -> Self { |
43 | slice::from_raw_parts_mut(data:this.0, len:this.1) |
44 | } |
45 | |
46 | #[inline ] |
47 | fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T> { |
48 | this.0 |
49 | } |
50 | #[inline ] |
51 | fn len(this: &Self::Internal) -> usize { |
52 | this.1 |
53 | } |
54 | } |
55 | |
56 | unsafe impl<T, const N: usize> Container<T> for [MaybeUninit<T>; N] { |
57 | type Internal = UnsafeCell<[MaybeUninit<T>; N]>; |
58 | |
59 | fn into_internal(self) -> Self::Internal { |
60 | UnsafeCell::new(self) |
61 | } |
62 | unsafe fn from_internal(this: Self::Internal) -> Self { |
63 | this.into_inner() |
64 | } |
65 | |
66 | #[inline ] |
67 | fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T> { |
68 | this.get() as *mut _ |
69 | } |
70 | #[inline ] |
71 | fn len(_: &Self::Internal) -> usize { |
72 | N |
73 | } |
74 | } |
75 | |
76 | #[cfg (feature = "alloc" )] |
77 | unsafe impl<T> Container<T> for Vec<MaybeUninit<T>> { |
78 | type Internal = Self; |
79 | |
80 | fn into_internal(self) -> Self::Internal { |
81 | self |
82 | } |
83 | unsafe fn from_internal(this: Self::Internal) -> Self { |
84 | this |
85 | } |
86 | |
87 | #[inline ] |
88 | fn as_mut_ptr(this: &Self::Internal) -> *mut MaybeUninit<T> { |
89 | this.as_ptr() as *mut _ |
90 | } |
91 | #[inline ] |
92 | fn len(this: &Self::Internal) -> usize { |
93 | this.len() |
94 | } |
95 | } |
96 | |
97 | /// Wrapper for container that provides multiple write access to it. |
98 | pub(crate) struct SharedStorage<T, C: Container<T>> { |
99 | container: C::Internal, |
100 | _p: PhantomData<T>, |
101 | } |
102 | |
103 | unsafe impl<T, C: Container<T>> Sync for SharedStorage<T, C> where T: Send {} |
104 | |
105 | impl<T, C: Container<T>> SharedStorage<T, C> { |
106 | /// Create new storage. |
107 | /// |
108 | /// *Panics if container is empty.* |
109 | pub fn new(container: C) -> Self { |
110 | let internal = container.into_internal(); |
111 | assert!(C::len(&internal) > 0); |
112 | Self { |
113 | container: internal, |
114 | _p: PhantomData, |
115 | } |
116 | } |
117 | |
118 | /// Get the length of the container. |
119 | #[inline ] |
120 | pub fn len(&self) -> NonZeroUsize { |
121 | unsafe { NonZeroUsize::new_unchecked(C::len(&self.container)) } |
122 | } |
123 | |
124 | /// Returns a pair of slices between `head` and `tail` positions in the storage. |
125 | /// |
126 | /// For more information see [`ring_buffer_ranges`]. |
127 | /// |
128 | /// # Safety |
129 | /// |
130 | /// There only single reference to any item allowed to exist at the time. |
131 | pub unsafe fn as_mut_slices( |
132 | &self, |
133 | head: usize, |
134 | tail: usize, |
135 | ) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) { |
136 | let ranges = ring_buffer_ranges(self.len(), head, tail); |
137 | let ptr = C::as_mut_ptr(&self.container); |
138 | ( |
139 | slice::from_raw_parts_mut(ptr.add(ranges.0.start), ranges.0.len()), |
140 | slice::from_raw_parts_mut(ptr.add(ranges.1.start), ranges.1.len()), |
141 | ) |
142 | } |
143 | |
144 | /// Returns underlying container. |
145 | pub fn into_inner(self) -> C { |
146 | unsafe { C::from_internal(self.container) } |
147 | } |
148 | } |
149 | |