···11use core::{cell::UnsafeCell, hint::unreachable_unchecked, sync::atomic::AtomicU8};
2233#[derive(PartialEq, Eq, Clone, Copy, Debug)]
44-pub enum Ptr {
44+pub(crate) enum Ptr {
55 Value1,
66 Value2,
77}
8899impl Ptr {
1010- #[inline]
1111- pub fn switch(&mut self) {
1010+ pub(crate) fn switch(&mut self) {
1211 *self = match self {
1312 Ptr::Value1 => Self::Value2,
1413 Ptr::Value2 => Self::Value1,
1514 };
1615 }
1717-}
1616+1717+ /// SAFETY: Assumes no read bits (lower two) are set
1818+ pub(crate) unsafe fn from_u8_no_read(value: u8) -> Self {
1919+ match value {
2020+ 0b000 => Self::Value1,
2121+ 0b100 => Self::Value2,
2222+ // SAFETY: unsafe fn. communicated in docs
2323+ _ => unsafe { unreachable_unchecked() },
2424+ }
2525+ }
18261919-impl From<u8> for Ptr {
2020- #[inline]
2121- fn from(value: u8) -> Self {
2727+ /// ignores potentially set read bits.
2828+ /// SAFETY: no bits except the for bottom three can be set
2929+ pub(crate) unsafe fn from_u8_ignore_read(value: u8) -> Self {
2230 match value & 0b100 {
2331 0b000 => Self::Value1,
2432 0b100 => Self::Value2,
2525- // SAFETY: Internal Library Value only.
3333+ // SAFETY: unsafe fn. communicated in docs
2634 _ => unsafe { unreachable_unchecked() },
2735 }
2836 }
2937}
30383139#[derive(Debug)]
3232-pub enum ReadState {
4040+pub(crate) enum ReadState {
3341 None,
3442 Value(Ptr),
3535- /// Is written before loading the ptr value and then instantly overwritten with the specific ptr value
3636- /// This makes sure the Writer doesn't swap and load between loading the ptr and setting the read
3737- Both,
3843}
39444045impl ReadState {
4146 /// is writing on the passed ptr parameter valid with the current read state?
4247 #[inline]
4343- pub fn can_write(&self, ptr: Ptr) -> bool {
4848+ pub(crate) fn can_write(&self, ptr: Ptr) -> bool {
4449 match self {
4550 ReadState::None => true,
4651 ReadState::Value(p) => *p != ptr,
4747- ReadState::Both => false,
4852 }
4953 }
5050-}
51545252-impl From<Ptr> for ReadState {
5353- #[inline]
5454- fn from(value: Ptr) -> Self {
5555- Self::Value(value)
5656- }
5757-}
5858-5959-impl From<u8> for ReadState {
6060- #[inline]
6161- fn from(value: u8) -> Self {
5555+ /// SAFETY: only the read state bits are set
5656+ pub(crate) unsafe fn from_u8_ignore_ptr(value: u8) -> Self {
6257 match value & 0b011 {
6358 0b00 => Self::None,
6459 0b01 => Self::Value(Ptr::Value1),
6560 0b10 => Self::Value(Ptr::Value2),
6666- 0b11 => Self::Both,
6761 // SAFETY: Internal Library Value only.
6862 _ => unsafe { unreachable_unchecked() },
6963 }
7064 }
7165}
72666767+impl From<Ptr> for ReadState {
6868+ #[inline]
6969+ fn from(value: Ptr) -> Self {
7070+ Self::Value(value)
7171+ }
7272+}
7373+7374#[derive(Debug)]
7474-pub struct Shared<T> {
7575+pub(crate) struct Shared<T> {
7576 pub value_1: UnsafeCell<T>,
7677 pub value_2: UnsafeCell<T>,
7778 /// bit 0: is value 1 being read
···8788unsafe impl<T: Send + Sync> Sync for Shared<T> {}
88898990impl<T> Shared<T> {
9090- pub fn get_value(&self, ptr: Ptr) -> &UnsafeCell<T> {
9191+ pub(crate) fn get_value(&self, ptr: Ptr) -> &UnsafeCell<T> {
9192 match ptr {
9293 Ptr::Value1 => &self.value_1,
9394 Ptr::Value2 => &self.value_2,
+51-31
simple-left-right/src/lib.rs
···2121 clippy::missing_safety_doc,
2222 clippy::undocumented_unsafe_blocks
2323)]
2424-2524#![cfg_attr(not(feature = "std"), no_std)]
26252726extern crate alloc;
28272928#[cfg(feature = "std")]
3030-use std::thread;
3131-#[cfg(feature = "std")]
3229use core::time::Duration;
3030+#[cfg(feature = "std")]
3131+use std::thread;
33323433use core::{
3535- hint::assert_unchecked,
3434+ cell::UnsafeCell,
3635 marker::PhantomData,
3736 mem::MaybeUninit,
3837 ops::Deref,
3939- sync::atomic::{fence, AtomicU8, Ordering}
3838+ sync::atomic::{fence, AtomicU8, Ordering},
4039};
41404241use alloc::{collections::vec_deque::VecDeque, sync::Arc};
···105104 // sets the corresponding read bit to the write ptr bit
106105 // happens as a single atomic operation so the 'double read' state isn't needed
107106 // ptr bit doesnt get changed
107107+ // always Ok, as the passed closure never returns None
108108 let update_result =
109109 self.inner
110110 .state
111111 .fetch_update(Ordering::Relaxed, Ordering::Acquire, |value| {
112112 // SAFETY: At this point no Read bit is set, as creating a ReadGuard requires a &mut Reader and the Guard holds the &mut Reader
113113 unsafe {
114114- assert_unchecked(value & 0b011 == 0);
115115- }
116116- match value.into() {
117117- Ptr::Value1 => Some(0b001),
118118- Ptr::Value2 => Some(0b110),
114114+ match Ptr::from_u8_no_read(value) {
115115+ Ptr::Value1 => Some(0b001),
116116+ Ptr::Value2 => Some(0b110),
117117+ }
119118 }
120119 });
121120122122- // SAFETY: the passed clorusure always returns Some, so fetch_update never returns Err
123123- let ptr = unsafe { update_result.unwrap_unchecked().into() };
121121+ // here the read ptr and read state of update_result match. maybe the atomic was already changed, but that doesn't matter.
122122+ // we continue working with the state that we set.
123123+124124+ // SAFETY: the passed closure always returns Some, so fetch_update never returns Err
125125+ let ptr = unsafe {
126126+ // here it doesn't matter if we create the Ptr from the read bits or from the ptr bit, as they match
127127+ Ptr::from_u8_ignore_read(update_result.unwrap_unchecked())
128128+ };
124129125125- // SAFETY: the Writer always sets the Read bit to the opposite of its write_ptr
130130+ // SAFETY: the Writer allowed the read on this value because the ptr bit was set. The read bit has been set
126131 let data = unsafe { self.inner.get_value(ptr).get().as_ref().unwrap_unchecked() };
127132128128- // SAFETY: the read_state is set to the value that is being
129133 ReadGuard {
130134 data,
131135 state: &self.inner.state,
···150154 pub fn swap(self) {}
151155152156 /// Gets the value currently being written to.
153153- #[must_use]
154157 pub fn read(&self) -> &T {
155158 self.writer.read()
156159 }
···160163 fn get_data_mut(&mut self) -> &mut T {
161164 // SAFETY: When creating the writeguad it is checked that the reader doesnt have access to the same data
162165 // This function requires &mut self so there also isn't any ref created by writeguard.
163163- unsafe { self.get_data_ptr().as_mut().unwrap() }
164164- }
165165-166166- fn get_data_ptr(&self) -> *mut T {
167167- self.writer.shared.get_value(self.writer.write_ptr).get()
166166+ // SAFETY: the ptr is never null, therefore unwrap_unchecked
167167+ unsafe {
168168+ self.writer
169169+ .shared
170170+ .get_value(self.writer.write_ptr)
171171+ .get()
172172+ .as_mut()
173173+ .unwrap_unchecked()
174174+ }
168175 }
169176}
170177···264271 /// Blocks if the Reader has a `ReadGuard` pointing to the old value.
265272 ///
266273 /// Uses a Spinlock because for anything else the OS needs to be involved and `Reader` can't talk to the OS.
267267- #[cfg(not(feature = "std"))]
268274 pub fn lock(&mut self) -> WriteGuard<'_, T, O> {
269275 let backoff = crossbeam_utils::Backoff::new();
270276···272278 // operation has to be aquire, but only the time it breaks the loop
273279 let state = self.shared.state.load(Ordering::Relaxed);
274280275275- if ReadState::from(state).can_write(self.write_ptr) {
281281+ // SAFETY: is in state internal only value which is only set by library code
282282+ let state = unsafe { ReadState::from_u8_ignore_ptr(state) };
283283+284284+ if state.can_write(self.write_ptr) {
276285 // make the load operation aquire only when it actually breaks the loop
277286 // the important (last) load is aquire, while all loads before are relaxed
278287 fence(Ordering::Acquire);
···288297 }
289298290299 /// Blocks if the Reader has a `ReadGuard` pointing to the old value.
291291- ///
300300+ ///
292301 /// Uses a spin-lock, because the `Reader` can't talk to the OS. Sleeping and Yielding is done to avoid wasting cycles.
293302 /// Equivalent to ´lock´, except that it starts sleeping the given duration after a certaint point until the lock could be aquired.
294303 #[cfg(feature = "std")]
295295- pub fn lock(&mut self, sleep: Duration) -> WriteGuard<'_, T, O> {
304304+ pub fn sleep_lock(&mut self, sleep: Duration) -> WriteGuard<'_, T, O> {
296305 let backoff = crossbeam_utils::Backoff::new();
297306298307 loop {
299308 // operation has to be aquire, but only the time it breaks the loop
300309 let state = self.shared.state.load(Ordering::Relaxed);
301310302302- if ReadState::from(state).can_write(self.write_ptr) {
311311+ // SAFETY: is in state internal only value which is only set by library code
312312+ let state = unsafe { ReadState::from_u8_ignore_ptr(state) };
313313+314314+ if state.can_write(self.write_ptr) {
303315 // make the load operation aquire, only when it actually breaks the loop
304316 // the important (last) load is aquire, while all loads before are relaxed
305317 fence(Ordering::Acquire);
···328340 // operation has to be aquire, but only the time it breaks the loop
329341 let state = self.shared.state.load(Ordering::Relaxed);
330342331331- if ReadState::from(state).can_write(self.write_ptr) {
343343+ // SAFETY: is in state internal only value which is only set by library code
344344+ let state = unsafe { ReadState::from_u8_ignore_ptr(state) };
345345+346346+ if state.can_write(self.write_ptr) {
332347 // make the load operation aquire, only when it actually breaks the loop
333348 // the important (last) load is aquire, while all loads before are relaxed
334349 fence(Ordering::Acquire);
···352367 pub fn try_lock(&mut self) -> Option<WriteGuard<'_, T, O>> {
353368 let state = self.shared.state.load(Ordering::Acquire);
354369355355- if ReadState::from(state).can_write(self.write_ptr) {
370370+ // SAFETY: is in state internal only value which is only set by library code
371371+ let state = unsafe { ReadState::from_u8_ignore_ptr(state) };
372372+373373+ if state.can_write(self.write_ptr) {
356374 // SAFETY: ReadState allows this
357375 unsafe { Some(WriteGuard::new(self)) }
358376 } else {
···371389 let shared = unsafe {
372390 let shared_ptr = Arc::get_mut(&mut shared).unwrap_unchecked().as_mut_ptr();
373391 (&raw mut (*shared_ptr).state).write(AtomicU8::new(0b000));
374374- (&raw mut (*shared_ptr).value_1).cast::<T>().write(value.clone());
375375- (&raw mut (*shared_ptr).value_2).cast::<T>().write(value);
392392+ UnsafeCell::raw_get(&raw const (*shared_ptr).value_1).write(value.clone());
393393+ UnsafeCell::raw_get(&raw const (*shared_ptr).value_1).write(value);
376394 shared.assume_init()
377395 };
378396···388406 /// Creates a new Writer by calling `T::default()` twice to create the two values
389407 ///
390408 /// Default impl of T needs to give the same result every time. Not upholding this doens't lead to UB, but turns the library basically useless
409409+ ///
410410+ /// Could leak a T object if T::default() panics.
391411 fn default() -> Self {
392412 let mut shared: Arc<MaybeUninit<Shared<T>>> = Arc::new_uninit();
393413···396416 let shared = unsafe {
397417 let shared_ptr = Arc::get_mut(&mut shared).unwrap_unchecked().as_mut_ptr();
398418 (&raw mut (*shared_ptr).state).write(AtomicU8::new(0b000));
399399- (&raw mut (*shared_ptr).value_1).cast::<T>().write(T::default());
400400- (&raw mut (*shared_ptr).value_2).cast::<T>().write(T::default());
419419+ UnsafeCell::raw_get(&raw const (*shared_ptr).value_1).write(T::default());
420420+ UnsafeCell::raw_get(&raw const (*shared_ptr).value_1).write(T::default());
401421 shared.assume_init()
402422 };
403423
···1212categories = ["audio"]
13131414[features]
1515-async = ["dep:async-io", "dep:futures-lite", "dep:async-channel", "simple-left-right/async"]
1515+async = ["dep:async-io", "dep:futures-lite", "dep:async-channel", "dep:futures-io", "simple-left-right/async"]
16161717[dependencies]
1818async-io = { version = "2.3.4", optional = true }
1919futures-lite = { version = "2.3.0", optional = true }
2020async-channel = { version = "2.3.1", optional = true }
2121+futures-io = { version = "0.3.31", optional = true }
2122# added a couple features to it. pull requests don' really progress
2223basedrop = "0.1.2" # miri reports Race Condition. Wait for fix or pull inside
2324cpal = "0.15.3"
+7-1
tracker-engine/src/live_audio.rs
···180180 }
181181 }
182182183183+ // unsure wether i want to use this or untyped_callback
184184+ // also relevant when cpal gets made into a generic that maybe this gets useful
185185+ #[expect(dead_code)]
183186 pub fn get_typed_callback<S: cpal::SizedSample + cpal::FromSample<f32>>(
184187 mut self,
185188 ) -> impl FnMut(&mut [S], &cpal::OutputCallbackInfo) {
186186- move |data, info| {
189189+ move |data, _info| {
187190 assert_eq!(
188191 data.len(),
189192 usize::try_from(self.config.buffer_size).unwrap()
···197200 }
198201}
199202203203+// only used for testing
204204+// if not testing is unused
205205+#[allow(dead_code)]
200206fn sine(output: &mut [[f32; 2]], sample_rate: f32) {
201207 let mut sample_clock = 0f32;
202208 for frame in output {
+1-1
tracker-engine/src/manager.rs
···167167 /// Spinloops until no more ReadGuard to the old value exists
168168 pub fn edit_song(&mut self) -> SongEdit<'_> {
169169 SongEdit {
170170- song: self.song.lock(Self::SPIN_SLEEP),
170170+ song: self.song.sleep_lock(Self::SPIN_SLEEP),
171171 gc: &mut self.gc
172172 }
173173 }