use core::cell::UnsafeCell;
use core::sync::atomic::{
AtomicU32,
Ordering::{self, *},
};
#[repr(transparent)]
pub struct AtomicF32(UnsafeCell<f32>);
unsafe impl Send for AtomicF32 {}
unsafe impl Sync for AtomicF32 {}
const _: [(); core::mem::size_of::<AtomicU32>()] = [(); core::mem::size_of::<UnsafeCell<f32>>()];
const _: [(); core::mem::align_of::<AtomicU32>()] = [(); core::mem::align_of::<UnsafeCell<f32>>()];
impl AtomicF32 {
#[inline]
pub const fn new(float: f32) -> Self {
Self(UnsafeCell::new(float))
}
#[inline]
pub fn get_mut(&mut self) -> &mut f32 {
unsafe { &mut *self.0.get() }
}
#[inline]
pub fn into_inner(self) -> f32 {
self.0.into_inner()
}
#[inline]
pub fn load(&self, ordering: Ordering) -> f32 {
f32::from_bits(self.as_atomic_bits().load(ordering))
}
#[inline]
pub fn store(&self, value: f32, ordering: Ordering) {
self.as_atomic_bits().store(value.to_bits(), ordering);
}
#[inline]
pub fn swap(&self, new_value: f32, ordering: Ordering) -> f32 {
f32::from_bits(self.as_atomic_bits().swap(new_value.to_bits(), ordering))
}
#[inline]
pub fn compare_and_swap(&self, current: f32, new: f32, order: Ordering) -> f32 {
f32::from_bits(self.as_atomic_bits().compare_and_swap(
current.to_bits(),
new.to_bits(),
order,
))
}
#[inline]
pub fn compare_exchange(
&self,
current: f32,
new: f32,
success: Ordering,
failure: Ordering,
) -> Result<f32, f32> {
match self.as_atomic_bits().compare_exchange(
current.to_bits(),
new.to_bits(),
success,
failure,
) {
Ok(v) => Ok(f32::from_bits(v)),
Err(v) => Err(f32::from_bits(v)),
}
}
#[inline]
pub fn compare_exchange_weak(
&self,
current: f32,
new: f32,
success: Ordering,
failure: Ordering,
) -> Result<f32, f32> {
match self.as_atomic_bits().compare_exchange_weak(
current.to_bits(),
new.to_bits(),
success,
failure,
) {
Ok(v) => Ok(f32::from_bits(v)),
Err(v) => Err(f32::from_bits(v)),
}
}
#[inline]
pub fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
mut update: F,
) -> Result<f32, f32>
where
F: FnMut(f32) -> Option<f32>,
{
let res = self
.as_atomic_bits()
.fetch_update(set_order, fetch_order, |prev| {
update(f32::from_bits(prev)).map(f32::to_bits)
});
match res {
Ok(o) => Ok(f32::from_bits(o)),
Err(e) => Err(f32::from_bits(e)),
}
}
#[inline]
fn update_with<F>(&self, order: Ordering, mut update: F) -> f32
where
F: FnMut(f32) -> f32,
{
self.fetch_update(order, super::fail_order_for(order), |f| Some(update(f)))
.unwrap()
}
#[inline]
pub fn fetch_add(&self, val: f32, order: Ordering) -> f32 {
self.update_with(order, |f| f + val)
}
#[inline]
pub fn fetch_sub(&self, val: f32, order: Ordering) -> f32 {
self.update_with(order, |f| f - val)
}
#[inline]
pub fn fetch_abs(&self, order: Ordering) -> f32 {
f32::from_bits(self.as_atomic_bits().fetch_and(0x7fff_ffff, order))
}
#[inline]
pub fn fetch_neg(&self, order: Ordering) -> f32 {
f32::from_bits(self.as_atomic_bits().fetch_xor(0x8000_0000, order))
}
#[inline]
pub fn fetch_min(&self, value: f32, order: Ordering) -> f32 {
self.update_with(order, |f| f.min(value))
}
#[inline]
pub fn fetch_max(&self, value: f32, order: Ordering) -> f32 {
self.update_with(order, |f| f.max(value))
}
#[inline]
pub fn as_atomic_bits(&self) -> &AtomicU32 {
unsafe { &*(&self.0 as *const _ as *const AtomicU32) }
}
}
impl Default for AtomicF32 {
#[inline]
fn default() -> Self {
Self::from(0.0)
}
}
impl core::fmt::Debug for AtomicF32 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.load(SeqCst).fmt(f)
}
}
impl From<f32> for AtomicF32 {
#[inline]
fn from(f: f32) -> Self {
Self::new(f)
}
}