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]
#[cfg(target_has_atomic = "32")]
pub fn swap(&self, new_value: f32, ordering: Ordering) -> f32 {
f32::from_bits(self.as_atomic_bits().swap(new_value.to_bits(), ordering))
}
#[inline]
#[allow(deprecated)]
#[cfg(target_has_atomic = "32")]
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]
#[cfg(target_has_atomic = "32")]
pub fn compare_exchange(
&self,
current: f32,
new: f32,
success: Ordering,
failure: Ordering,
) -> Result<f32, f32> {
convert_result(self.as_atomic_bits().compare_exchange(
current.to_bits(),
new.to_bits(),
success,
failure,
))
}
#[inline]
#[cfg(target_has_atomic = "32")]
pub fn compare_exchange_weak(
&self,
current: f32,
new: f32,
success: Ordering,
failure: Ordering,
) -> Result<f32, f32> {
convert_result(self.as_atomic_bits().compare_exchange_weak(
current.to_bits(),
new.to_bits(),
success,
failure,
))
}
#[inline]
#[cfg(target_has_atomic = "32")]
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)
});
convert_result(res)
}
#[inline]
#[cfg(target_has_atomic = "32")]
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]
#[cfg(target_has_atomic = "32")]
pub fn fetch_add(&self, val: f32, order: Ordering) -> f32 {
self.update_with(order, |f| f + val)
}
#[inline]
#[cfg(target_has_atomic = "32")]
pub fn fetch_sub(&self, val: f32, order: Ordering) -> f32 {
self.update_with(order, |f| f - val)
}
#[inline]
#[cfg(target_has_atomic = "32")]
pub fn fetch_abs(&self, order: Ordering) -> f32 {
f32::from_bits(self.as_atomic_bits().fetch_and(0x7fff_ffff, order))
}
#[inline]
#[cfg(target_has_atomic = "32")]
pub fn fetch_neg(&self, order: Ordering) -> f32 {
f32::from_bits(self.as_atomic_bits().fetch_xor(0x8000_0000, order))
}
#[inline]
#[cfg(target_has_atomic = "32")]
pub fn fetch_min(&self, value: f32, order: Ordering) -> f32 {
self.update_with(order, |f| f.min(value))
}
#[inline]
#[cfg(target_has_atomic = "32")]
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)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for AtomicF32 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_f32(self.load(Ordering::SeqCst))
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for AtomicF32 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
f32::deserialize(deserializer).map(AtomicF32::new)
}
}
#[inline(always)]
fn convert_result(r: Result<u32, u32>) -> Result<f32, f32> {
r.map(f32::from_bits).map_err(f32::from_bits)
}
impl PartialEq for AtomicF32 {
#[inline]
fn eq(&self, o: &AtomicF32) -> bool {
self.load(Relaxed) == o.load(Relaxed)
}
}