Skip to content

Commit

Permalink
merge with upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
flippette committed Jul 13, 2024
2 parents 7f1118e + 3ad046b commit 0204e37
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 2.1.0 - 2024-04-26

- Added `ConstStaticCell` (#14)

## 2.0.0 - 2023-11-02

- Do not enable feature `critical-section` in `portable-atomic`. In targets that need
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "static_cell"
version = "2.0.0"
version = "2.1.0"
edition = "2021"
description = "Statically allocated, initialized at runtime cell."
license = "MIT OR Apache-2.0"
Expand Down
74 changes: 73 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ use portable_atomic::{AtomicBool, Ordering};
/// to the contents permanently changes it to "full". This allows that reference to be valid
/// forever.
///
/// If your value can be initialized as a `const` value, consider using [`ConstStaticCell`]
/// instead if you only need to take the value at runtime.
///
/// See the [crate-level docs](crate) for usage.
pub struct StaticCell<T> {
used: AtomicBool,
Expand Down Expand Up @@ -131,6 +134,75 @@ impl<T> StaticCell<T> {
}
}

// ---

/// Statically allocated and initialized, taken at runtime cell.
///
/// It has two states: "untaken" and "taken". It is created "untaken", and obtaining a reference
/// to the contents permanently changes it to "taken". This allows that reference to be valid
/// forever.
///
/// If your value can be const defined, for example a large, zero filled buffer used for DMA
/// or other scratch memory usage, `ConstStaticCell` can be used to guarantee the initializer
/// will never take up stack memory.
///
/// If your values are all zero initialized, the resulting `ConstStaticCell` should be placed
/// in `.bss`, not taking flash space for initialization either.
///
/// See the [crate-level docs](crate) for usage.
pub struct ConstStaticCell<T> {
taken: AtomicBool,
val: UnsafeCell<T>,
}

unsafe impl<T> Send for ConstStaticCell<T> {}
unsafe impl<T> Sync for ConstStaticCell<T> {}

impl<T> ConstStaticCell<T> {
/// Create a new, empty `ConstStaticCell`.
///
/// It can be taken at runtime with [`ConstStaticCell::take()`] or similar methods.
#[inline]
pub const fn new(value: T) -> Self {
Self {
taken: AtomicBool::new(false),
val: UnsafeCell::new(value),
}
}

/// Take the `ConstStaticCell`, returning a mutable reference to it.
///
/// # Panics
///
/// Panics if this `ConstStaticCell` was already taken.
#[inline]
#[allow(clippy::mut_from_ref)]
pub fn take(&'static self) -> &'static mut T {
if let Some(val) = self.try_take() {
val
} else {
panic!("`ConstStaticCell` is already taken, it can't be taken twice")
}
}

/// Try to take the `ConstStaticCell`, returning None if it was already taken
#[inline]
#[allow(clippy::mut_from_ref)]
pub fn try_take(&'static self) -> Option<&'static mut T> {
if self
.taken
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
// SAFETY: We just checked that the value is not yet taken and marked it as taken.
let val = unsafe { &mut *self.val.get() };
Some(val)
} else {
None
}
}
}

/// Convert a `T` to a `&'static mut T`.
///
/// The macro declares a `static StaticCell` and then initializes it when run, returning the `&'static mut`.
Expand Down Expand Up @@ -166,7 +238,7 @@ macro_rules! make_static {
$(#[$m])*
static STATIC_CELL: $crate::StaticCell<T> = $crate::StaticCell::new();
#[deny(unused_attributes)]
let (x,) = unsafe { STATIC_CELL.uninit().write(($val,)) };
let (x,) = STATIC_CELL.uninit().write(($val,));
x
}};
}

0 comments on commit 0204e37

Please sign in to comment.