Remove Forever, switch to static_cell.
This commit is contained in:
@ -31,3 +31,4 @@ futures-util = { version = "0.3.17", features = [ "channel" ] }
|
||||
|
||||
# Enable critical-section implementation for std, for tests
|
||||
critical-section = { version = "1.1", features = ["std"] }
|
||||
static_cell = "1.0"
|
||||
|
@ -471,10 +471,10 @@ mod tests {
|
||||
use futures_executor::ThreadPool;
|
||||
use futures_timer::Delay;
|
||||
use futures_util::task::SpawnExt;
|
||||
use static_cell::StaticCell;
|
||||
|
||||
use super::*;
|
||||
use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
|
||||
use crate::Forever;
|
||||
|
||||
fn capacity<T, const N: usize>(c: &ChannelState<T, N>) -> usize {
|
||||
c.queue.capacity() - c.queue.len()
|
||||
@ -549,8 +549,8 @@ mod tests {
|
||||
async fn receiver_receives_given_try_send_async() {
|
||||
let executor = ThreadPool::new().unwrap();
|
||||
|
||||
static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 3>> = Forever::new();
|
||||
let c = &*CHANNEL.put(Channel::new());
|
||||
static CHANNEL: StaticCell<Channel<CriticalSectionRawMutex, u32, 3>> = StaticCell::new();
|
||||
let c = &*CHANNEL.init(Channel::new());
|
||||
let c2 = c;
|
||||
assert!(executor
|
||||
.spawn(async move {
|
||||
@ -571,8 +571,8 @@ mod tests {
|
||||
async fn senders_sends_wait_until_capacity() {
|
||||
let executor = ThreadPool::new().unwrap();
|
||||
|
||||
static CHANNEL: Forever<Channel<CriticalSectionRawMutex, u32, 1>> = Forever::new();
|
||||
let c = &*CHANNEL.put(Channel::new());
|
||||
static CHANNEL: StaticCell<Channel<CriticalSectionRawMutex, u32, 1>> = StaticCell::new();
|
||||
let c = &*CHANNEL.init(Channel::new());
|
||||
assert!(c.try_send(1).is_ok());
|
||||
|
||||
let c2 = c;
|
||||
|
@ -1,95 +0,0 @@
|
||||
use core::cell::UnsafeCell;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use atomic_polyfill::{AtomicBool, Ordering};
|
||||
|
||||
/// Type with static lifetime that may be written to once at runtime.
|
||||
///
|
||||
/// This may be used to initialize static objects at runtime, typically in the init routine.
|
||||
/// This is useful for objects such as Embassy's RTC, which cannot be initialized in a const
|
||||
/// context.
|
||||
///
|
||||
/// Note: IF a global mutable variable is desired, use a CriticalSectionMutex or ThreadModeMutex instead.
|
||||
///
|
||||
/// ```
|
||||
/// use embassy_util::Forever;
|
||||
/// // Using an integer for the sake of keeping this example self-contained,
|
||||
/// // see https://github.com/embassy-rs/embassy/wiki/Getting-Started for a more "proper" example.
|
||||
/// static SOME_INT: Forever<u32> =Forever::new();
|
||||
///
|
||||
/// // put returns a mutable pointer to the object stored in the forever, which may then be passed
|
||||
/// // around.
|
||||
/// let mut x = SOME_INT.put(42);
|
||||
/// assert_eq!(*x, 42);
|
||||
/// ```
|
||||
pub struct Forever<T> {
|
||||
used: AtomicBool,
|
||||
t: UnsafeCell<MaybeUninit<T>>,
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for Forever<T> {}
|
||||
unsafe impl<T> Sync for Forever<T> {}
|
||||
|
||||
impl<T> Forever<T> {
|
||||
/// Create a new `Forever`.
|
||||
#[inline(always)]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
used: AtomicBool::new(false),
|
||||
t: UnsafeCell::new(MaybeUninit::uninit()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Store a value in this `Forever`, returning a mutable reference to it.
|
||||
///
|
||||
/// Using this method, the compiler usually constructs `val` in the stack and then moves
|
||||
/// it into the `Forever`. If `T` is big, this is likely to cause stack overflows.
|
||||
/// Considering using [`Signal::put_with`] instead, which will construct it in-place inside the `Forever`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this `Forever` already has a value stored in it.
|
||||
#[inline(always)]
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub fn put(&'static self, val: T) -> &'static mut T {
|
||||
self.put_with(|| val)
|
||||
}
|
||||
|
||||
/// Store the closure return value in this `Forever`, returning a mutable reference to it.
|
||||
///
|
||||
/// The advantage over [`Forever::put`] is that this method allows the closure to construct
|
||||
/// the `T` value in-place directly inside the `Forever`, saving stack space.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if this `Forever` already has a value stored in it.
|
||||
#[inline(always)]
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub fn put_with(&'static self, val: impl FnOnce() -> T) -> &'static mut T {
|
||||
if self
|
||||
.used
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
panic!("Forever.put() called multiple times");
|
||||
}
|
||||
|
||||
let p: &'static mut MaybeUninit<T> = unsafe { &mut *self.t.get() };
|
||||
p.write(val())
|
||||
}
|
||||
|
||||
/// Unsafely get a mutable reference to the contents of this Forever.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is undefined behavior if:
|
||||
///
|
||||
/// - The `Forever` has not been initialized yet (with `put' or `put_with`), or
|
||||
/// - A reference to the contents (mutable or not) already exists.
|
||||
#[inline(always)]
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub unsafe fn steal(&self) -> &mut T {
|
||||
let p: &mut MaybeUninit<T> = &mut *self.t.get();
|
||||
p.assume_init_mut()
|
||||
}
|
||||
}
|
@ -16,10 +16,8 @@ pub mod mutex;
|
||||
pub mod pipe;
|
||||
pub mod waitqueue;
|
||||
|
||||
mod forever;
|
||||
mod select;
|
||||
mod yield_now;
|
||||
|
||||
pub use forever::*;
|
||||
pub use select::*;
|
||||
pub use yield_now::*;
|
||||
|
@ -461,10 +461,10 @@ mod io_impls {
|
||||
mod tests {
|
||||
use futures_executor::ThreadPool;
|
||||
use futures_util::task::SpawnExt;
|
||||
use static_cell::StaticCell;
|
||||
|
||||
use super::*;
|
||||
use crate::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
|
||||
use crate::Forever;
|
||||
|
||||
fn capacity<const N: usize>(c: &PipeState<N>) -> usize {
|
||||
N - c.buffer.len()
|
||||
@ -528,8 +528,8 @@ mod tests {
|
||||
async fn receiver_receives_given_try_write_async() {
|
||||
let executor = ThreadPool::new().unwrap();
|
||||
|
||||
static CHANNEL: Forever<Pipe<CriticalSectionRawMutex, 3>> = Forever::new();
|
||||
let c = &*CHANNEL.put(Pipe::new());
|
||||
static CHANNEL: StaticCell<Pipe<CriticalSectionRawMutex, 3>> = StaticCell::new();
|
||||
let c = &*CHANNEL.init(Pipe::new());
|
||||
let c2 = c;
|
||||
let f = async move {
|
||||
assert_eq!(c2.try_write(&[42]), Ok(1));
|
||||
|
Reference in New Issue
Block a user