atomic_float/atomic_f32.rs
1use core::cell::UnsafeCell;
2use core::sync::atomic::{
3 AtomicU32,
4 Ordering::{self, *},
5};
6
7/// A floating point type which can be safely shared between threads.
8///
9/// This type has the same in-memory representation as the underlying floating
10/// point type, [`f32`].
11///
12/// See the module documentation for [core::sync::atomic] for information about
13/// the portability of various atomics (this one is mostly as portable as
14/// [`AtomicU32`](core::sync::atomic::AtomicU32), with the caveat that we
15/// additionally that the platform support 32-bit floats).
16///
17/// # Example
18///
19/// The intended use case is situations like this:
20///
21/// ```
22/// # use atomic_float::AtomicF32;
23/// # use std::sync::atomic::Ordering;
24/// static DELTA_TIME: AtomicF32 = AtomicF32::new(1.0);
25///
26/// // In some main simulation loop:
27/// # fn compute_delta_time() -> f32 { 1.0 / 60.0 }
28/// DELTA_TIME.store(compute_delta_time(), Ordering::Release);
29///
30/// // elsewhere, perhaps on other threads:
31/// let dt = DELTA_TIME.load(Ordering::Acquire);
32/// // Use `dt` to compute simulation...
33/// ```
34///
35/// As well as any other cases where use of locking would be too substantial of
36/// overhead.
37///
38/// Note that when used like this (with Acquire and Release orderings), on
39/// x86_64 this compiles to the same code as you would get from a C++ global,
40/// (or a Rust `static mut`), while offering full synchronization.
41///
42/// (While caveats exist, the cases where you'd need the total order guaranteed
43/// by [SeqCst](core::sync::atomic::Ordering::SeqCst) for something like
44/// [`AtomicF32`] seem very rare).
45///
46/// # Implementation
47///
48/// Note: These details are not part of the stability guarantee of this crate,
49/// and are subject to change without a semver-breaking change.
50///
51/// Under the hood we use a transparent `UnsafeCell<f32>`, and cast the
52/// `&UnsafeCell<f32>` to an [`&AtomicU32`](core::sync::atomic::AtomicU32) in
53/// order to perform atomic operations.
54///
55/// This means that we have the same ABI and layout as f32, and that some
56/// operations have a minimal cost (for example: on x86 all operations of
57/// equivalent or weaker ordering than `Release` stores/`Acquire` loads are
58/// essentially equivalent to non-atomic f32).
59///
60/// However, operations like [`fetch_add`](AtomicF32::fetch_add) are
61/// considerably slower than would be the case for integer atomics.
62#[repr(transparent)]
63pub struct AtomicF32(
64 // FIXME: Once we can do `f32::from_bits` in const fn, this should be an
65 // `AtomicU32` (or at least `UnsafeCell<u32>`).
66 UnsafeCell<f32>,
67);
68
69// SAFETY: We only ever access the underlying data by refcasting to AtomicU32,
70// which guarantees no data races.
71unsafe impl Send for AtomicF32 {}
72unsafe impl Sync for AtomicF32 {}
73
74// Static assertions that the layout is identical, we cite these in a safety
75// comment in `AtomicF32::atom()`. Note that the alignment check is stricter
76// than we need, as it would still be safe if `AtomicU32` is less strictly-
77// aligned than our `f32`. Unlike with `AtomicF64`, this is unlikely to occur.
78const _: [(); core::mem::size_of::<AtomicU32>()] = [(); core::mem::size_of::<UnsafeCell<f32>>()];
79const _: [(); core::mem::align_of::<AtomicU32>()] = [(); core::mem::align_of::<UnsafeCell<f32>>()];
80
81impl AtomicF32 {
82 /// Initialize a `AtomicF32` from an `f32`.
83 ///
84 /// # Example
85 ///
86 /// Use as a variable
87 ///
88 /// ```
89 /// # use atomic_float::AtomicF32;
90 /// # use std::sync::atomic::Ordering::Relaxed;
91 /// let x = AtomicF32::new(3.0f32);
92 /// assert_eq!(x.load(Relaxed), 3.0f32);
93 /// ```
94 ///
95 /// Use as a static:
96 ///
97 /// ```
98 /// # use atomic_float::AtomicF32;
99 /// # use std::sync::atomic::Ordering::Relaxed;
100 /// static A_STATIC: AtomicF32 = AtomicF32::new(800.0);
101 /// assert_eq!(A_STATIC.load(Relaxed), 800.0);
102 /// ```
103 #[inline]
104 pub const fn new(float: f32) -> Self {
105 Self(UnsafeCell::new(float))
106 }
107
108 /// Returns a mutable reference to the underlying float.
109 ///
110 /// This is safe because the mutable reference guarantees that no other
111 /// threads are concurrently accessing the atomic data.
112 ///
113 /// # Example
114 ///
115 /// ```
116 /// # use atomic_float::AtomicF32;
117 /// # use std::sync::atomic::Ordering;
118 /// let mut some_float = AtomicF32::new(1.0);
119 /// assert_eq!(*some_float.get_mut(), 1.0);
120 /// *some_float.get_mut() += 1.0;
121 /// assert_eq!(some_float.load(Ordering::SeqCst), 2.0);
122 /// ```
123 #[inline]
124 pub fn get_mut(&mut self) -> &mut f32 {
125 // SAFETY: the mutable reference guarantees unique ownership.
126 unsafe { &mut *self.0.get() }
127 }
128
129 /// Consumes the atomic and returns the contained value.
130 ///
131 /// This is safe because passing `self` by value guarantees that no other
132 /// threads are concurrently accessing the atomic data.
133 ///
134 /// # Example
135 ///
136 /// ```
137 /// # use atomic_float::AtomicF32;
138 /// let v = AtomicF32::new(6.0);
139 /// assert_eq!(v.into_inner(), 6.0f32);
140 /// ```
141 #[inline]
142 pub fn into_inner(self) -> f32 {
143 self.0.into_inner()
144 }
145
146 /// Loads a value from the atomic float.
147 ///
148 /// `load` takes an [`Ordering`] argument which describes the memory
149 /// ordering of this operation. Possible values are [`SeqCst`], [`Acquire`]
150 /// and [`Relaxed`].
151 ///
152 /// # Panics
153 ///
154 /// Panics if `ordering` is [`Release`] or [`AcqRel`].
155 ///
156 /// [`Ordering`]: core::sync::atomic::Ordering
157 /// [`Relaxed`]: core::sync::atomic::Ordering::Relaxed
158 /// [`Release`]: core::sync::atomic::Ordering::Release
159 /// [`Acquire`]: core::sync::atomic::Ordering::Acquire
160 /// [`AcqRel`]: core::sync::atomic::Ordering::AcqRel
161 /// [`SeqCst`]: core::sync::atomic::Ordering::SeqCst
162 ///
163 /// # Example
164 ///
165 /// ```
166 /// use atomic_float::AtomicF32;
167 /// use std::sync::atomic::Ordering;
168 /// let v = AtomicF32::new(22.5);
169 /// assert_eq!(v.load(Ordering::SeqCst), 22.5);
170 /// ```
171 #[inline]
172 pub fn load(&self, ordering: Ordering) -> f32 {
173 f32::from_bits(self.as_atomic_bits().load(ordering))
174 }
175
176 /// Store a value into the atomic float.
177 ///
178 /// `store` takes an [`Ordering`] argument which describes the memory
179 /// ordering of this operation. Possible values are [`SeqCst`], [`Release`]
180 /// and [`Relaxed`].
181 ///
182 /// # Panics
183 ///
184 /// Panics if `ordering` is [`Acquire`] or [`AcqRel`].
185 ///
186 /// [`Ordering`]: core::sync::atomic::Ordering
187 /// [`Relaxed`]: core::sync::atomic::Ordering::Relaxed
188 /// [`Release`]: core::sync::atomic::Ordering::Release
189 /// [`Acquire`]: core::sync::atomic::Ordering::Acquire
190 /// [`AcqRel`]: core::sync::atomic::Ordering::AcqRel
191 /// [`SeqCst`]: core::sync::atomic::Ordering::SeqCst
192 ///
193 /// # Example
194 ///
195 /// ```
196 /// use atomic_float::AtomicF32;
197 /// use std::sync::atomic::Ordering;
198 /// let v = AtomicF32::new(22.5);
199 /// assert_eq!(v.load(Ordering::SeqCst), 22.5);
200 /// v.store(30.0, Ordering::SeqCst);
201 /// assert_eq!(v.load(Ordering::SeqCst), 30.0);
202 /// ```
203 #[inline]
204 pub fn store(&self, value: f32, ordering: Ordering) {
205 self.as_atomic_bits().store(value.to_bits(), ordering);
206 }
207
208 /// Stores a value into the atomic float, returning the previous value.
209 ///
210 /// `swap` takes an [`Ordering`] argument which describes the memory ordering
211 /// of this operation. All ordering modes are possible. Note that using
212 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
213 /// using [`Release`] makes the load part [`Relaxed`].
214 ///
215 /// [`Ordering`]: core::sync::atomic::Ordering
216 /// [`Relaxed`]: core::sync::atomic::Ordering::Relaxed
217 /// [`Release`]: core::sync::atomic::Ordering::Release
218 /// [`Acquire`]: core::sync::atomic::Ordering::Acquire
219 ///
220 /// # Example
221 ///
222 /// ```
223 /// use atomic_float::AtomicF32;
224 /// use std::sync::atomic::Ordering;
225 /// let v = AtomicF32::new(4.5);
226 /// assert_eq!(v.swap(100.0, Ordering::Relaxed), 4.5);
227 /// assert_eq!(v.load(Ordering::Relaxed), 100.0);
228 /// ```
229 #[inline]
230 #[cfg(target_has_atomic = "32")]
231 pub fn swap(&self, new_value: f32, ordering: Ordering) -> f32 {
232 f32::from_bits(self.as_atomic_bits().swap(new_value.to_bits(), ordering))
233 }
234
235 /// Stores a value into the atomic float if the current value is *bitwise
236 /// identical* to the `current` value.
237 ///
238 /// The return value is always the previous value. If it is equal to
239 /// `current`, then the value was updated.
240 ///
241 /// `compare_and_swap` also takes an [`Ordering`] argument which describes
242 /// the memory ordering of this operation. Notice that even when using
243 /// `AcqRel`, the operation might fail and hence just perform an `Acquire`
244 /// load, but not have `Release` semantics. Using `Acquire` makes the store
245 /// part of this operation `Relaxed` if it happens, and using `Release`
246 /// makes the load part `Relaxed`.
247 ///
248 /// [`Ordering`]: core::sync::atomic::Ordering
249 ///
250 /// # Caveats
251 ///
252 /// As the `current` must be bitwise identical to the previous value, you
253 /// should not get the `current` value using any sort of arithmetic (both
254 /// because of rounding, and to avoid any situation where -0.0 and +0.0
255 /// would be compared). Additionally, on some platforms (WASM and ASM.js
256 /// currently) LLVM will canonicalize NaNs during loads, which can cause
257 /// unexpected behavior here — typically in the other direction (two values
258 /// being unexpectedly equal).
259 ///
260 /// In practice, typical patterns for CaS tend to avoid these issues, but
261 /// you're encouraged to avoid relying on the behavior of cas-family APIs in
262 /// the face of rounding, signed zero, and NaNs.
263 ///
264 /// # Example
265 ///
266 /// ```
267 /// # use atomic_float::AtomicF32;
268 /// # use std::sync::atomic::Ordering;
269 /// let v = AtomicF32::new(5.0);
270 /// assert_eq!(v.compare_and_swap(5.0, 10.0, Ordering::Relaxed), 5.0);
271 /// assert_eq!(v.load(Ordering::Relaxed), 10.0);
272 ///
273 /// assert_eq!(v.compare_and_swap(6.0, 12.0, Ordering::Relaxed), 10.0);
274 /// assert_eq!(v.load(Ordering::Relaxed), 10.0);
275 /// ```
276 #[inline]
277 #[allow(deprecated)]
278 #[cfg(target_has_atomic = "32")]
279 pub fn compare_and_swap(&self, current: f32, new: f32, order: Ordering) -> f32 {
280 f32::from_bits(self.as_atomic_bits().compare_and_swap(
281 current.to_bits(),
282 new.to_bits(),
283 order,
284 ))
285 }
286
287 /// Stores a value into the atomic float if the current value is the bitwise
288 /// identical as the `current` value.
289 ///
290 /// The return value is a result indicating whether the new value was
291 /// written and containing the previous value. On success this value is
292 /// guaranteed to be bitwise identical to `current`.
293 ///
294 /// `compare_exchange` takes two [`Ordering`] arguments to describe the
295 /// memory ordering of this operation. The first describes the required
296 /// ordering if the operation succeeds while the second describes the
297 /// required ordering when the operation fails. Using `Acquire` as success
298 /// ordering makes the store part of this operation `Relaxed`, and using
299 /// `Release` makes the successful load `Relaxed`. The failure ordering can
300 /// only be `SeqCst`, `Acquire` or `Relaxed` and must be equivalent to or
301 /// weaker than the success ordering.
302 ///
303 /// [`Ordering`]: core::sync::atomic::Ordering
304 ///
305 /// # Notes
306 ///
307 /// Note that in many cases, when `while` loops where the condition contains
308 /// a `compare_exchange` operation are better written to use a
309 /// [`compare_exchange_weak`](AtomicF32::compare_exchange_weak) in the
310 /// condition instead (as on weakly ordered platforms like ARM, the
311 /// `compare_exchange` operation itself can require a loop to perform).
312 ///
313 /// ## Caveats
314 ///
315 /// As the `current` parameter must be bitwise identical to the previous
316 /// value, you should not get the `current` value using any sort of
317 /// arithmetic (both because of rounding, and to avoid any situation where
318 /// -0.0 and +0.0 would be compared). Additionally, on Wasm, in some cases
319 /// `NaN` values have been known to cause problems for non-typical usage of
320 /// this API. See [`AtomicF32::as_atomic_bits`] if performing the
321 /// `compare_exchange` on the raw bits of this atomic float would solve an
322 /// issue for you.
323 ///
324 /// # Example
325 ///
326 /// ```
327 /// # use atomic_float::AtomicF32;
328 /// # use std::sync::atomic::Ordering::*;
329 /// let v = AtomicF32::new(5.0);
330 /// assert_eq!(v.compare_exchange(5.0, 10.0, Acquire, Relaxed), Ok(5.0));
331 /// assert_eq!(v.load(Relaxed), 10.0);
332 ///
333 /// assert_eq!(v.compare_exchange(6.0, 12.0, SeqCst, Relaxed), Err(10.0));
334 /// assert_eq!(v.load(Relaxed), 10.0);
335 /// ```
336 #[inline]
337 #[cfg(target_has_atomic = "32")]
338 pub fn compare_exchange(
339 &self,
340 current: f32,
341 new: f32,
342 success: Ordering,
343 failure: Ordering,
344 ) -> Result<f32, f32> {
345 convert_result(self.as_atomic_bits().compare_exchange(
346 current.to_bits(),
347 new.to_bits(),
348 success,
349 failure,
350 ))
351 }
352
353 /// Stores a value into the atomic integer if the current value is the same
354 /// as the `current` value.
355 ///
356 /// Unlike [`compare_exchange`](Self::compare_exchange), this function is
357 /// allowed to spuriously fail even when the comparison succeeds, which can
358 /// result in more efficient code on some platforms. The return value is a
359 /// result indicating whether the new value was written and containing the
360 /// previous value.
361 ///
362 /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the
363 /// memory ordering of this operation. The first describes the required
364 /// ordering if the operation succeeds while the second describes the
365 /// required ordering when the operation fails. Using `Acquire` as success
366 /// ordering makes the store part of this operation `Relaxed`, and using
367 /// `Release` makes the successful load `Relaxed`. The failure ordering can
368 /// only be `SeqCst`, `Acquire` or `Relaxed` and must be equivalent to or
369 /// weaker than the success ordering.
370 ///
371 /// [`Ordering`]: core::sync::atomic::Ordering
372 ///
373 /// ## Caveats
374 ///
375 /// As the `current` parameter must be bitwise identical to the previous
376 /// value, you should not get the `current` value using any sort of
377 /// arithmetic (both because of rounding, and to avoid any situation where
378 /// -0.0 and +0.0 would be compared). Additionally, on Wasm, in some cases
379 /// `NaN` values have been known to cause problems for non-typical usage of
380 /// this API. See [`AtomicF32::as_atomic_bits`] if performing the
381 /// `compare_exchange` on the raw bits of this atomic float would solve an
382 /// issue for you.
383 ///
384 /// # Example
385 ///
386 /// Note that this sort of CaS loop should generally use [`fetch_update`]
387 /// instead.
388 ///
389 /// [`fetch_update`]: AtomicF32::fetch_update
390 ///
391 /// ```
392 /// # use atomic_float::AtomicF32;
393 /// # use std::sync::atomic::Ordering::*;
394 /// let v = AtomicF32::new(5.0);
395 /// let mut old = v.load(Relaxed);
396 /// loop {
397 /// let new = old * 2.0;
398 /// match v.compare_exchange_weak(old, new, SeqCst, Relaxed) {
399 /// Ok(_) => break,
400 /// Err(x) => old = x,
401 /// }
402 /// }
403 /// ```
404 #[inline]
405 #[cfg(target_has_atomic = "32")]
406 pub fn compare_exchange_weak(
407 &self,
408 current: f32,
409 new: f32,
410 success: Ordering,
411 failure: Ordering,
412 ) -> Result<f32, f32> {
413 convert_result(self.as_atomic_bits().compare_exchange_weak(
414 current.to_bits(),
415 new.to_bits(),
416 success,
417 failure,
418 ))
419 }
420
421 /// Fetches the value, and applies a function to it that returns an optional
422 /// new value. Returns a `Result` of `Ok(previous_value)` if the function
423 /// returned `Some(_)`, else `Err(previous_value)`.
424 ///
425 /// Note: This may call the function multiple times if the value has been
426 /// changed from other threads in the meantime, as long as the function
427 /// returns `Some(_)`, but the function will have been applied only once to
428 /// the stored value.
429 ///
430 /// `fetch_update` takes two [`Ordering`] arguments to describe the memory
431 /// ordering of this operation. The first describes the required ordering
432 /// for when the operation finally succeeds while the second describes the
433 /// required ordering for loads. These correspond to the success and failure
434 /// orderings of [`compare_exchange`][AtomicF32::compare_exchange]
435 /// respectively.
436 ///
437 /// Using `Acquire` as success ordering makes the store part of this
438 /// operation `Relaxed`, and using `Release` makes the final successful load
439 /// `Relaxed`. The (failed) load ordering can only be `SeqCst`, `Acquire` or
440 /// `Relaxed` and must be equivalent to or weaker than the success ordering.
441 ///
442 /// [`Ordering`]: core::sync::atomic::Ordering
443 ///
444 /// # Example
445 ///
446 /// ```
447 /// # use atomic_float::AtomicF32;
448 /// # use std::sync::atomic::Ordering::*;
449 /// let x = AtomicF32::new(7.0);
450 ///
451 /// assert_eq!(x.fetch_update(SeqCst, SeqCst, |_| None), Err(7.0));
452 /// assert_eq!(x.fetch_update(SeqCst, SeqCst, |x| Some(x + 1.0)), Ok(7.0));
453 /// assert_eq!(x.fetch_update(SeqCst, SeqCst, |x| Some(x + 1.0)), Ok(8.0));
454 /// assert_eq!(x.load(SeqCst), 9.0);
455 /// ```
456 #[inline]
457 #[cfg(target_has_atomic = "32")]
458 pub fn fetch_update<F>(
459 &self,
460 set_order: Ordering,
461 fetch_order: Ordering,
462 mut update: F,
463 ) -> Result<f32, f32>
464 where
465 F: FnMut(f32) -> Option<f32>,
466 {
467 let res = self
468 .as_atomic_bits()
469 .fetch_update(set_order, fetch_order, |prev| {
470 update(f32::from_bits(prev)).map(f32::to_bits)
471 });
472 convert_result(res)
473 }
474
475 /// A (nonstandard) convenience wrapper around [`fetch_update`](Self::fetch_update).
476 ///
477 /// A call like:
478 ///
479 /// ```
480 /// # const _: &str = stringify!{
481 /// let res = atom.update_with(order, |f| update f...);
482 /// # };
483 /// ```
484 ///
485 /// Is morally equivalent to:
486 ///
487 /// ```
488 /// # const _: &str = stringify!{
489 /// let res = atom.fetch_update(
490 /// order,
491 /// failure_order_for(order),
492 /// |f| Some(update f...),
493 /// ).unwrap();
494 /// # };
495 /// ```
496 ///
497 /// Where `failure_order_for` returns the strongest failure order you'd be
498 /// allowed to pass into `fetch_update` given the success order, that is:
499 ///
500 /// ```
501 /// # const _: &str = stringify!{
502 /// fn failure_order_for(order: Ordering) -> Ordering {
503 /// Release | Relaxed => Relaxed,
504 /// Acquire | AcqRel => Acquire,
505 /// SeqCst => SeqCst,
506 /// }
507 /// # };
508 /// ```
509 #[inline]
510 #[cfg(target_has_atomic = "32")]
511 fn update_with<F>(&self, order: Ordering, mut update: F) -> f32
512 where
513 F: FnMut(f32) -> f32,
514 {
515 self.fetch_update(order, super::fail_order_for(order), |f| Some(update(f)))
516 .unwrap()
517 }
518
519 /// Adds to the current value, returning the previous value.
520 ///
521 /// Because this returns the previous value, you may want to call it like:
522 /// `atom.fetch_add(x, order) + x`
523 ///
524 /// # Examples
525 /// ```
526 /// # use atomic_float::AtomicF32;
527 /// # use std::sync::atomic::Ordering::*;
528 /// let x = AtomicF32::new(7.0);
529 ///
530 /// assert_eq!(x.fetch_add(2.0, Relaxed), 7.0);
531 /// assert_eq!(x.fetch_add(1.0, SeqCst), 9.0);
532 /// assert_eq!(x.fetch_add(-100.0, AcqRel), 10.0);
533 /// ```
534 #[inline]
535 #[cfg(target_has_atomic = "32")]
536 pub fn fetch_add(&self, val: f32, order: Ordering) -> f32 {
537 self.update_with(order, |f| f + val)
538 }
539
540 /// Subtract from the current value, returning the previous value.
541 ///
542 /// Because this returns the previous value, you may want to call it like:
543 /// `atom.fetch_sub(x, order) - x`
544 ///
545 /// Note: This operation uses [`fetch_update`](Self::fetch_update) under the hood, and is likely
546 /// to be slower than the equivalent operation for atomic integers.
547 ///
548 /// # Examples
549 /// ```
550 /// # use atomic_float::AtomicF32;
551 /// # use std::sync::atomic::Ordering::*;
552 /// let x = AtomicF32::new(7.0);
553 /// assert_eq!(x.fetch_sub(2.0, Relaxed), 7.0);
554 /// assert_eq!(x.fetch_sub(-1.0, SeqCst), 5.0);
555 /// assert_eq!(x.fetch_sub(0.5, AcqRel), 6.0);
556 /// ```
557 #[inline]
558 #[cfg(target_has_atomic = "32")]
559 pub fn fetch_sub(&self, val: f32, order: Ordering) -> f32 {
560 self.update_with(order, |f| f - val)
561 }
562
563 /// Produce the absolute value of the current value, returning the previous
564 /// value.
565 ///
566 /// # Examples
567 /// ```
568 /// # use atomic_float::AtomicF32;
569 /// # use std::sync::atomic::Ordering::*;
570 /// let x = AtomicF32::new(-7.0);
571 /// assert_eq!(x.fetch_abs(Relaxed), -7.0);
572 /// assert_eq!(x.fetch_abs(SeqCst), 7.0);
573 /// ```
574 #[inline]
575 #[cfg(target_has_atomic = "32")]
576 pub fn fetch_abs(&self, order: Ordering) -> f32 {
577 f32::from_bits(self.as_atomic_bits().fetch_and(0x7fff_ffff, order))
578 }
579
580 /// Negates the current value, returning the previous value.
581 ///
582 /// As a result of returning the previous value, you may want to invoke it like:
583 /// `-atom.fetch_neg(Relaxed)`.
584 ///
585 ///
586 /// # Examples
587 /// ```
588 /// # use atomic_float::AtomicF32;
589 /// # use std::sync::atomic::Ordering::*;
590 /// let x = AtomicF32::new(-7.0);
591 /// assert_eq!(x.fetch_neg(Relaxed), -7.0);
592 /// assert_eq!(x.fetch_neg(SeqCst), 7.0);
593 /// assert_eq!(x.fetch_neg(AcqRel), -7.0);
594 /// ```
595 #[inline]
596 #[cfg(target_has_atomic = "32")]
597 pub fn fetch_neg(&self, order: Ordering) -> f32 {
598 f32::from_bits(self.as_atomic_bits().fetch_xor(0x8000_0000, order))
599 }
600
601 /// Minimum with the current value.
602 ///
603 /// Finds the minimum of the current value and the argument `val`, and sets
604 /// the new value to the result.
605 ///
606 /// Returns the previous value. Because of this, you may want to call it
607 /// like: `atom.fetch_min(x, order).min(x)`
608 ///
609 /// Note: This operation uses [`fetch_update`](Self::fetch_update) under the
610 /// hood, and is likely to be slower than the equivalent operation for
611 /// atomic integers.
612 ///
613 /// # Examples
614 ///
615 /// ```
616 /// # use atomic_float::AtomicF32;
617 /// # use std::sync::atomic::Ordering;
618 ///
619 /// let foo = AtomicF32::new(23.0);
620 /// assert_eq!(foo.fetch_min(42.0, Ordering::Relaxed), 23.0);
621 /// assert_eq!(foo.load(Ordering::Relaxed), 23.0);
622 /// assert_eq!(foo.fetch_min(22.0, Ordering::Relaxed), 23.0);
623 /// assert_eq!(foo.load(Ordering::Relaxed), 22.0);
624 /// ```
625 #[inline]
626 #[cfg(target_has_atomic = "32")]
627 pub fn fetch_min(&self, value: f32, order: Ordering) -> f32 {
628 self.update_with(order, |f| f.min(value))
629 }
630
631 /// Maximum with the current value.
632 ///
633 /// Finds the maximum of the current value and the argument `val`, and sets
634 /// the new value to the result.
635 ///
636 /// Returns the previous value. Because of this, you may want to call it
637 /// like: `atom.fetch_max(x, order).max(x)`
638 ///
639 /// Note: This operation uses [`fetch_update`](Self::fetch_update) under the
640 /// hood, and is likely to be slower than the equivalent operation for
641 /// atomic integers.
642 ///
643 /// # Examples
644 ///
645 /// ```
646 /// # use atomic_float::AtomicF32;
647 /// # use std::sync::atomic::Ordering;
648 ///
649 /// let foo = AtomicF32::new(23.0);
650 /// assert_eq!(foo.fetch_max(22.0, Ordering::Relaxed), 23.0);
651 /// assert_eq!(foo.load(Ordering::Relaxed), 23.0);
652 /// assert_eq!(foo.fetch_max(42.0, Ordering::Relaxed), 23.0);
653 /// assert_eq!(foo.load(Ordering::Relaxed), 42.0);
654 /// ```
655 #[inline]
656 #[cfg(target_has_atomic = "32")]
657 pub fn fetch_max(&self, value: f32, order: Ordering) -> f32 {
658 self.update_with(order, |f| f.max(value))
659 }
660
661 /// Returns a reference to an atomic integer which can be used to access the
662 /// atomic float's underlying bits in a thread safe manner.
663 ///
664 /// This is essentially a `transmute::<&Self, &AtomicU32>(self)`, and is
665 /// zero cost.
666 ///
667 /// # Motivation
668 ///
669 /// This is exposed as an escape hatch because of the caveats around the
670 /// `AtomicF32` CaS-family APIs ([`compare_and_swap`], [`compare_exchange`],
671 /// [`compare_exchange_weak`], ...) and the notion of bitwise identicality
672 /// which they require being somewhat problematic for NaNs, especially on
673 /// targets like Wasm (see [rust-lang/rust#73328]).
674 ///
675 /// [`compare_and_swap`]: AtomicU32::compare_and_swap
676 /// [`compare_exchange`]: AtomicU32::compare_exchange
677 /// [`compare_exchange_weak`]: AtomicU32::compare_exchange_weak
678 /// [rust-lang/rust#73328]: https://github.com/rust-lang/rust/issues/73328
679 ///
680 /// In general despite how bad this might sound, in practice we're fairly
681 /// safe: LLVM almost never optimizes through atomic operations, this
682 /// library is written to try to avoid potential issues from most naive
683 /// usage, and I'm optimistic the situation will clean itself up in the
684 /// short-to-medium-term future.
685 ///
686 /// However, if you need peace of mind, or find yourself in a case where you
687 /// suspect you're hitting this issue, you can access the underlying atomic
688 /// value using this function.
689 ///
690 /// # Examples
691 ///
692 /// ```
693 /// # use atomic_float::AtomicF32;
694 /// # use std::sync::atomic::Ordering;
695 /// let v = AtomicF32::new(22.5);
696 /// assert_eq!(v.as_atomic_bits().load(Ordering::Relaxed), 22.5f32.to_bits());
697 /// ```
698 #[inline]
699 pub fn as_atomic_bits(&self) -> &AtomicU32 {
700 // Safety: All potentially shared reads/writes go through this, and the
701 // static assertions above ensure that AtomicU32 and UnsafeCell<f32> are
702 // compatible as pointers.
703 unsafe { &*(&self.0 as *const _ as *const AtomicU32) }
704 }
705}
706
707/// Return a zero-initialized atomic.
708///
709/// # Example
710///
711/// ```
712/// # use atomic_float::AtomicF32;
713/// # use core::sync::atomic::Ordering;
714/// let x = AtomicF32::default();
715/// assert_eq!(x.load(Ordering::SeqCst), 0.0);
716/// ```
717impl Default for AtomicF32 {
718 #[inline]
719 fn default() -> Self {
720 Self::from(0.0)
721 }
722}
723
724/// Equivalent to `<f32 as core::fmt::Debug>::fmt`.
725///
726/// # Example
727///
728/// ```
729/// # use atomic_float::AtomicF32;
730/// # use core::sync::atomic::Ordering;
731/// let v = AtomicF32::new(40.0);
732/// assert_eq!(format!("{:?}", v), format!("{:?}", 40.0f32));
733/// ```
734impl core::fmt::Debug for AtomicF32 {
735 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
736 self.load(SeqCst).fmt(f)
737 }
738}
739
740/// Equivalent to `AtomicF32::new`.
741///
742/// # Example
743///
744/// ```
745/// # use atomic_float::AtomicF32;
746/// # use core::sync::atomic::Ordering;
747/// let v = AtomicF32::from(10.0);
748/// assert_eq!(v.load(Ordering::SeqCst), 10.0);
749/// ```
750impl From<f32> for AtomicF32 {
751 #[inline]
752 fn from(f: f32) -> Self {
753 Self::new(f)
754 }
755}
756
757#[cfg(feature = "serde")]
758/// Serializes the AtomicF32
759///
760/// The value is loaded with the `Ordering::SeqCst` and then serializes
761/// it as a normal `f32`. The information about the object being atomic is lost.
762impl serde::Serialize for AtomicF32 {
763 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
764 where
765 S: serde::Serializer,
766 {
767 serializer.serialize_f32(self.load(Ordering::SeqCst))
768 }
769}
770
771#[cfg(feature = "serde")]
772/// Deserializes the AtomicF32
773///
774/// Attempts to deserialize f32 and, if successful, creates a new
775/// AtomicF32 with this value.
776impl<'de> serde::Deserialize<'de> for AtomicF32 {
777 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
778 where
779 D: serde::Deserializer<'de>,
780 {
781 f32::deserialize(deserializer).map(AtomicF32::new)
782 }
783}
784
785#[inline(always)]
786fn convert_result(r: Result<u32, u32>) -> Result<f32, f32> {
787 r.map(f32::from_bits).map_err(f32::from_bits)
788}
789
790// XXX: This is dubious since the actual atomic types don't implement this, but
791// I need it to use `serde_test`, so I might as well add it.
792/// Compare two [`AtomicF32`]s.
793///
794/// ```
795/// # use atomic_float::AtomicF32;
796/// # use std::sync::atomic::Ordering;
797/// let a = AtomicF32::new(1.0);
798/// a.fetch_add(1.0, Ordering::Relaxed);
799/// assert_ne!(a, AtomicF32::new(1.0));
800/// assert_eq!(a, AtomicF32::new(2.0));
801/// ```
802///
803/// # Caveats
804/// Relaxed ordering is used for each load, so additional fencing (or avoiding
805/// the use of this `PartialEq` implementation) may be desirable.
806///
807/// Additionally, this is implemented in terms of `f32`'s `PartialEq`, so NaNs
808/// will compare as inequal. For example:
809/// ```
810/// # use atomic_float::AtomicF32;
811/// let a = AtomicF32::new(f32::NAN);
812/// assert_ne!(a, a);
813/// ```
814impl PartialEq for AtomicF32 {
815 #[inline]
816 fn eq(&self, o: &AtomicF32) -> bool {
817 self.load(Relaxed) == o.load(Relaxed)
818 }
819}