Skip to content

Commit 250475e

Browse files
committed
[atomic] Initial commit of Atomic<T>
gherrit-pr-id: Gc89c7a052aa2609ae71d4db8531f55dab2fd4306
1 parent c6a9490 commit 250475e

File tree

3 files changed

+221
-2
lines changed

3 files changed

+221
-2
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/atomic.rs

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
// Copyright 2026 The Fuchsia Authors
2+
//
3+
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4+
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5+
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6+
// This file may not be copied, modified, or distributed except according to
7+
// those terms.
8+
9+
//! TODO
10+
11+
use core::{
12+
marker::PhantomData,
13+
sync::atomic::{AtomicU16, AtomicU32, AtomicU64, AtomicU8, Ordering},
14+
};
15+
16+
/// TODO
17+
///
18+
/// # Safety
19+
///
20+
/// TODO
21+
pub unsafe trait HasAtomic {
22+
#[doc(hidden)]
23+
type Atomic: Send + Sync + AtomicOps;
24+
25+
/// # Safety
26+
///
27+
/// `atomic` must be bit-valid for `Self`.
28+
#[doc(hidden)]
29+
unsafe fn from_atomic(atomic: <Self::Atomic as AtomicOps>::Value) -> Self;
30+
#[doc(hidden)]
31+
fn into_atomic(slf: Self) -> <Self::Atomic as AtomicOps>::Value;
32+
}
33+
34+
/// # Safety
35+
///
36+
/// TODO
37+
#[doc(hidden)]
38+
pub unsafe trait AtomicSelector<const N: usize> {
39+
type AtomicType;
40+
}
41+
42+
/// # Safety
43+
///
44+
/// TODO
45+
#[doc(hidden)]
46+
pub unsafe trait AtomicOps {
47+
type Value;
48+
49+
fn new(value: Self::Value) -> Self;
50+
fn load(&self, ordering: Ordering) -> Self::Value;
51+
fn store(&self, value: Self::Value, ordering: Ordering);
52+
}
53+
54+
macro_rules! impl_atomic_selector {
55+
($atomic:ty [$value:ty]; $($size:expr),+) => {
56+
// SAFETY: TODO
57+
unsafe impl AtomicOps for $atomic {
58+
type Value = $value;
59+
60+
#[inline(always)]
61+
fn new(value: Self::Value) -> Self {
62+
Self::new(value)
63+
}
64+
65+
#[inline(always)]
66+
fn load(&self, ordering: Ordering) -> Self::Value {
67+
self.load(ordering)
68+
}
69+
70+
#[inline(always)]
71+
fn store(&self, value: Self::Value, ordering: Ordering) {
72+
self.store(value, ordering)
73+
}
74+
}
75+
76+
$(
77+
// SAFETY: TODO
78+
unsafe impl AtomicSelector<$size> for () {
79+
type AtomicType = $atomic;
80+
}
81+
)+
82+
};
83+
}
84+
85+
impl_atomic_selector!(AtomicU8 [u8]; 1);
86+
impl_atomic_selector!(AtomicU16 [u16]; 2);
87+
impl_atomic_selector!(AtomicU32 [u32]; 3, 4);
88+
impl_atomic_selector!(AtomicU64 [u64]; 5, 6, 7, 8);
89+
90+
/// TODO
91+
#[macro_export]
92+
macro_rules! impl_atomic {
93+
($t:ty) => {
94+
// SAFETY: TODO
95+
unsafe impl HasAtomic for $t
96+
where
97+
Self: $crate::IntoBytes,
98+
{
99+
type Atomic = <() as AtomicSelector<{ core::mem::size_of::<$t>() }>>::AtomicType;
100+
101+
#[inline(always)]
102+
unsafe fn from_atomic(_atomic: <Self::Atomic as AtomicOps>::Value) -> Self {
103+
todo!()
104+
}
105+
106+
#[inline(always)]
107+
fn into_atomic(_slf: Self) -> <Self::Atomic as AtomicOps>::Value {
108+
todo!()
109+
}
110+
}
111+
};
112+
}
113+
114+
impl_atomic!(u8);
115+
116+
/// TODO
117+
#[repr(transparent)]
118+
#[allow(missing_copy_implementations, missing_debug_implementations)]
119+
pub struct Atomic<T: HasAtomic> {
120+
// INVARIANT: The first `size_of::<T>()` bytes of `atomic` have the same
121+
// validity as `T`, and logically own a `T`.
122+
atomic: T::Atomic,
123+
_marker: PhantomData<T>,
124+
}
125+
126+
// TODO: Impl traits (Copy, Clone, Debug, Send, Sync, etc).
127+
128+
impl<T: HasAtomic> Atomic<T> {
129+
/// TODO
130+
#[inline(always)]
131+
#[must_use]
132+
pub fn new(v: T) -> Self {
133+
let atomic = T::Atomic::new(T::into_atomic(v));
134+
Self { atomic, _marker: PhantomData }
135+
}
136+
137+
/// TODO
138+
#[inline]
139+
#[must_use]
140+
pub fn load(&self, ordering: Ordering) -> T {
141+
let v = self.atomic.load(ordering);
142+
// SAFETY: TODO
143+
unsafe { T::from_atomic(v) }
144+
}
145+
146+
/// TODO
147+
#[inline]
148+
pub fn store(&self, v: T, ordering: Ordering) {
149+
let atomic = T::into_atomic(v);
150+
self.atomic.store(atomic, ordering)
151+
}
152+
}
153+
154+
#[cfg(test)]
155+
mod tests {
156+
use super::*;
157+
use crate::{Immutable, IntoBytes, KnownLayout};
158+
159+
#[derive(IntoBytes, KnownLayout, Immutable, Clone, Copy, Debug, PartialEq)]
160+
#[repr(C)]
161+
struct MyStruct {
162+
a: u32,
163+
}
164+
165+
#[derive(IntoBytes, KnownLayout, Immutable, Clone, Copy, Debug, PartialEq)]
166+
#[repr(u8)]
167+
enum MyEnum {
168+
A = 0,
169+
B = 1,
170+
}
171+
172+
#[test]
173+
fn test_atomic_u32() {
174+
let a = Atomic::new(10u32);
175+
assert_eq!(a.load(Ordering::SeqCst), 10);
176+
a.store(20, Ordering::SeqCst);
177+
assert_eq!(a.load(Ordering::SeqCst), 20);
178+
assert_eq!(a.swap(30, Ordering::SeqCst), 20);
179+
assert_eq!(a.load(Ordering::SeqCst), 30);
180+
}
181+
182+
#[test]
183+
fn test_atomic_struct() {
184+
let s1 = MyStruct { a: 10 };
185+
let s2 = MyStruct { a: 20 };
186+
let a = Atomic::new(s1);
187+
assert_eq!(a.load(Ordering::SeqCst), s1);
188+
a.store(s2, Ordering::SeqCst);
189+
assert_eq!(a.load(Ordering::SeqCst), s2);
190+
}
191+
192+
#[test]
193+
fn test_atomic_enum() {
194+
let a = Atomic::new(MyEnum::A);
195+
assert_eq!(a.load(Ordering::SeqCst), MyEnum::A);
196+
a.store(MyEnum::B, Ordering::SeqCst);
197+
assert_eq!(a.load(Ordering::SeqCst), MyEnum::B);
198+
}
199+
200+
#[test]
201+
fn test_compare_exchange() {
202+
let a = Atomic::new(10u32);
203+
let res = a.compare_exchange(10, 20, Ordering::SeqCst, Ordering::SeqCst);
204+
assert_eq!(res, Ok(10));
205+
assert_eq!(a.load(Ordering::SeqCst), 20);
206+
let res = a.compare_exchange(10, 30, Ordering::SeqCst, Ordering::SeqCst);
207+
assert_eq!(res, Err(20));
208+
assert_eq!(a.load(Ordering::SeqCst), 20);
209+
}
210+
211+
#[test]
212+
fn test_fetch_update() {
213+
let a = Atomic::new(10u32);
214+
let res = a.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |v| Some(v + 1));
215+
assert_eq!(res, Ok(10));
216+
assert_eq!(a.load(Ordering::SeqCst), 11);
217+
}
218+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ extern crate test;
334334
#[macro_use]
335335
pub mod util;
336336

337+
pub mod atomic;
337338
pub mod byte_slice;
338339
pub mod byteorder;
339340
mod deprecated;

0 commit comments

Comments
 (0)