Skip to main content

fuchsia_loom/
lib.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// These macros apply `#[cfg]`s to each item, avoid repeating the same config
6// settings, and cut down on the line noise.
7
8#[cfg(loom)]
9pub use ::loom;
10
11#[cfg(loom)]
12macro_rules! loom {
13    ($($tt:tt)*) => { $($tt)* }
14}
15
16#[cfg(not(loom))]
17macro_rules! loom {
18    ($($tt:tt)*) => {};
19}
20
21#[cfg(loom)]
22macro_rules! not_loom {
23    ($($tt:tt)*) => {};
24}
25
26#[cfg(not(loom))]
27macro_rules! not_loom {
28    ($($tt:tt)*) => { $($tt)* }
29}
30
31pub mod cell {
32    loom! {
33        pub use loom::cell::UnsafeCell;
34    }
35    not_loom! {
36        pub struct UnsafeCell<T: ?Sized>(core::cell::UnsafeCell<T>);
37
38        impl<T: ?Sized> UnsafeCell<T> {
39            #[inline]
40            pub fn new(value: T) -> Self
41            where
42                T: Sized,
43            {
44                Self(core::cell::UnsafeCell::new(value))
45            }
46
47            #[inline]
48            pub fn with_mut<F, R>(&self, f: F) -> R
49            where
50                F: FnOnce(*mut T) -> R,
51            {
52                f(self.0.get())
53            }
54
55            #[inline]
56            pub fn with<F, R>(&self, f: F) -> R
57            where
58                F: FnOnce(*const T) -> R,
59            {
60                f(self.0.get())
61            }
62        }
63    }
64}
65
66pub mod future {
67    loom! {
68        pub use loom::future::AtomicWaker;
69    }
70    not_loom! {
71        pub struct AtomicWaker(futures::task::AtomicWaker);
72
73        impl AtomicWaker {
74            #[inline]
75            pub fn new() -> Self {
76                Self(futures::task::AtomicWaker::new())
77            }
78
79            #[inline]
80            pub fn register_by_ref(&self, waker: &core::task::Waker) {
81                self.0.register(waker);
82            }
83
84            #[inline]
85            pub fn wake(&self) {
86                self.0.wake();
87            }
88        }
89    }
90}
91
92pub mod hint {
93    loom! {
94        pub use loom::hint::unreachable_unchecked;
95    }
96    not_loom! {
97        pub use core::hint::unreachable_unchecked;
98    }
99}
100
101pub mod sync {
102    loom! {
103        pub use loom::sync::{Arc, Mutex};
104    }
105    not_loom! {
106        pub use std::sync::{Arc, Mutex};
107    }
108
109    pub mod atomic {
110        macro_rules! define_atomic {
111            ($atomic:ident, $prim:ident) => {
112                loom! {
113                    pub use loom::sync::atomic::$atomic;
114                }
115                not_loom! {
116                    pub struct $atomic(core::sync::atomic::$atomic);
117
118                    impl $atomic {
119                        #[inline]
120                        pub fn new(v: $prim) -> Self {
121                            Self(core::sync::atomic::$atomic::new(v))
122                        }
123
124                        #[inline]
125                        pub fn with_mut<R>(&mut self, f: impl FnOnce(&mut $prim) -> R) -> R {
126                            f(self.0.get_mut())
127                        }
128
129                        #[inline]
130                        pub fn load(&self, order: Ordering) -> $prim {
131                            self.0.load(order)
132                        }
133
134                        #[inline]
135                        pub fn store(&self, val: $prim, order: Ordering) {
136                            self.0.store(val, order)
137                        }
138
139                        #[inline]
140                        pub fn fetch_add(&self, val: $prim, order: Ordering) -> $prim {
141                            self.0.fetch_add(val, order)
142                        }
143
144                        #[inline]
145                        pub fn fetch_sub(&self, val: $prim, order: Ordering) -> $prim {
146                            self.0.fetch_sub(val, order)
147                        }
148
149                        #[inline]
150                        pub fn fetch_or(&self, val: $prim, order: Ordering) -> $prim {
151                            self.0.fetch_or(val, order)
152                        }
153                    }
154                }
155            };
156        }
157
158        define_atomic!(AtomicU8, u8);
159        define_atomic!(AtomicU16, u16);
160        define_atomic!(AtomicU32, u32);
161        define_atomic!(AtomicU64, u64);
162        define_atomic!(AtomicUsize, usize);
163        define_atomic!(AtomicI8, i8);
164        define_atomic!(AtomicI16, i16);
165        define_atomic!(AtomicI32, i32);
166        define_atomic!(AtomicI64, i64);
167        define_atomic!(AtomicIsize, isize);
168
169        loom! {
170            pub use loom::sync::atomic::AtomicBool;
171        }
172        not_loom! {
173            pub struct AtomicBool(core::sync::atomic::AtomicBool);
174
175            impl AtomicBool {
176                #[inline]
177                pub fn new(v: bool) -> Self {
178                    Self(core::sync::atomic::AtomicBool::new(v))
179                }
180
181                #[inline]
182                pub fn load(&self, order: Ordering) -> bool {
183                    self.0.load(order)
184                }
185
186                #[inline]
187                pub fn store(&self, val: bool, order: Ordering) {
188                    self.0.store(val, order)
189                }
190            }
191        }
192
193        pub use core::sync::atomic::Ordering;
194    }
195
196    pub mod mpsc {
197        loom! {
198            pub use loom::sync::mpsc::{channel, Sender, Receiver};
199        }
200        not_loom! {
201            pub use std::sync::mpsc::{channel, Sender, Receiver};
202        }
203
204        pub use std::sync::mpsc::TryRecvError;
205    }
206}