Skip to content

Commit 8c9e681

Browse files
committed
Reduce number of cfg for race
1 parent 207fa02 commit 8c9e681

File tree

3 files changed

+218
-209
lines changed

3 files changed

+218
-209
lines changed

src/lib.rs

Lines changed: 1 addition & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,190 +1051,4 @@ pub mod sync {
10511051
///
10521052
/// This module does not require `std` feature.
10531053
#[cfg(feature = "unstable")]
1054-
pub mod race {
1055-
use core::{
1056-
num::NonZeroUsize,
1057-
sync::atomic::{AtomicUsize, Ordering},
1058-
};
1059-
1060-
#[cfg(feature = "alloc")]
1061-
use alloc::boxed::Box;
1062-
#[cfg(feature = "alloc")]
1063-
use core::{marker::PhantomData, ptr, sync::atomic::AtomicPtr};
1064-
1065-
#[derive(Default, Debug)]
1066-
pub struct OnceNonZeroUsize {
1067-
inner: AtomicUsize,
1068-
}
1069-
1070-
impl OnceNonZeroUsize {
1071-
pub const fn new() -> OnceNonZeroUsize {
1072-
OnceNonZeroUsize { inner: AtomicUsize::new(0) }
1073-
}
1074-
1075-
pub fn get(&self) -> Option<NonZeroUsize> {
1076-
let val = self.inner.load(Ordering::Acquire);
1077-
NonZeroUsize::new(val)
1078-
}
1079-
1080-
pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> {
1081-
let val = self.inner.compare_and_swap(0, value.get(), Ordering::AcqRel);
1082-
if val == 0 {
1083-
Ok(())
1084-
} else {
1085-
Err(())
1086-
}
1087-
}
1088-
1089-
pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize
1090-
where
1091-
F: FnOnce() -> NonZeroUsize,
1092-
{
1093-
enum Void {}
1094-
match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) {
1095-
Ok(val) => val,
1096-
Err(void) => match void {},
1097-
}
1098-
}
1099-
1100-
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
1101-
where
1102-
F: FnOnce() -> Result<NonZeroUsize, E>,
1103-
{
1104-
let val = self.inner.load(Ordering::Acquire);
1105-
let res = match NonZeroUsize::new(val) {
1106-
Some(it) => it,
1107-
None => {
1108-
let mut val = f()?.get();
1109-
let old_val = self.inner.compare_and_swap(0, val, Ordering::AcqRel);
1110-
if old_val != 0 {
1111-
val = old_val;
1112-
}
1113-
unsafe { NonZeroUsize::new_unchecked(val) }
1114-
}
1115-
};
1116-
Ok(res)
1117-
}
1118-
}
1119-
1120-
#[derive(Default, Debug)]
1121-
pub struct OnceBool {
1122-
inner: OnceNonZeroUsize,
1123-
}
1124-
1125-
impl OnceBool {
1126-
fn from_usize(value: NonZeroUsize) -> bool {
1127-
value.get() == 1
1128-
}
1129-
fn to_usize(value: bool) -> NonZeroUsize {
1130-
unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) }
1131-
}
1132-
1133-
pub const fn new() -> OnceBool {
1134-
OnceBool { inner: OnceNonZeroUsize::new() }
1135-
}
1136-
1137-
pub fn get(&self) -> Option<bool> {
1138-
self.inner.get().map(OnceBool::from_usize)
1139-
}
1140-
1141-
pub fn set(&self, value: bool) -> Result<(), ()> {
1142-
self.inner.set(OnceBool::to_usize(value))
1143-
}
1144-
1145-
pub fn get_or_init<F>(&self, f: F) -> bool
1146-
where
1147-
F: FnOnce() -> bool,
1148-
{
1149-
OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f())))
1150-
}
1151-
1152-
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E>
1153-
where
1154-
F: FnOnce() -> Result<bool, E>,
1155-
{
1156-
self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize)
1157-
}
1158-
}
1159-
1160-
#[derive(Default, Debug)]
1161-
#[cfg(feature = "alloc")]
1162-
pub struct OnceBox<T> {
1163-
inner: AtomicPtr<T>,
1164-
ghost: PhantomData<Option<Box<T>>>,
1165-
}
1166-
1167-
#[cfg(feature = "alloc")]
1168-
impl<T> Drop for OnceBox<T> {
1169-
fn drop(&mut self) {
1170-
let ptr = *self.inner.get_mut();
1171-
if !ptr.is_null() {
1172-
drop(unsafe { Box::from_raw(ptr) })
1173-
}
1174-
}
1175-
}
1176-
1177-
#[cfg(feature = "alloc")]
1178-
impl<T> OnceBox<T> {
1179-
pub const fn new() -> OnceBox<T> {
1180-
OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
1181-
}
1182-
1183-
pub fn get(&self) -> Option<&T> {
1184-
let ptr = self.inner.load(Ordering::Acquire);
1185-
if ptr.is_null() {
1186-
return None;
1187-
}
1188-
Some(unsafe { &*ptr })
1189-
}
1190-
1191-
// Result<(), Box<T>> here?
1192-
pub fn set(&self, value: T) -> Result<(), ()> {
1193-
let ptr = Box::into_raw(Box::new(value));
1194-
if ptr.is_null() {
1195-
drop(unsafe { Box::from_raw(ptr) });
1196-
return Err(());
1197-
}
1198-
Ok(())
1199-
}
1200-
1201-
pub fn get_or_init<F>(&self, f: F) -> &T
1202-
where
1203-
F: FnOnce() -> T,
1204-
{
1205-
enum Void {}
1206-
match self.get_or_try_init(|| Ok::<T, Void>(f())) {
1207-
Ok(val) => val,
1208-
Err(void) => match void {},
1209-
}
1210-
}
1211-
1212-
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
1213-
where
1214-
F: FnOnce() -> Result<T, E>,
1215-
{
1216-
let mut ptr = self.inner.load(Ordering::Acquire);
1217-
1218-
if ptr.is_null() {
1219-
let val = f()?;
1220-
ptr = Box::into_raw(Box::new(val));
1221-
let old_ptr = self.inner.compare_and_swap(ptr::null_mut(), ptr, Ordering::AcqRel);
1222-
if !old_ptr.is_null() {
1223-
drop(unsafe { Box::from_raw(ptr) });
1224-
ptr = old_ptr;
1225-
}
1226-
};
1227-
Ok(unsafe { &*ptr })
1228-
}
1229-
}
1230-
1231-
/// ```compile_fail
1232-
/// struct S(*mut ());
1233-
/// unsafe impl Sync for S {}
1234-
///
1235-
/// fn share<T: Sync>(_: &T) {}
1236-
/// share(&once_cell::race::OnceBox::<S>::new());
1237-
/// ```
1238-
#[cfg(feature = "alloc")]
1239-
unsafe impl<T: Sync + Send> Sync for OnceBox<T> {}
1240-
}
1054+
pub mod race;

src/race.rs

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
use core::{
2+
num::NonZeroUsize,
3+
sync::atomic::{AtomicUsize, Ordering},
4+
};
5+
6+
#[derive(Default, Debug)]
7+
pub struct OnceNonZeroUsize {
8+
inner: AtomicUsize,
9+
}
10+
11+
impl OnceNonZeroUsize {
12+
pub const fn new() -> OnceNonZeroUsize {
13+
OnceNonZeroUsize { inner: AtomicUsize::new(0) }
14+
}
15+
16+
pub fn get(&self) -> Option<NonZeroUsize> {
17+
let val = self.inner.load(Ordering::Acquire);
18+
NonZeroUsize::new(val)
19+
}
20+
21+
pub fn set(&self, value: NonZeroUsize) -> Result<(), ()> {
22+
let val = self.inner.compare_and_swap(0, value.get(), Ordering::AcqRel);
23+
if val == 0 {
24+
Ok(())
25+
} else {
26+
Err(())
27+
}
28+
}
29+
30+
pub fn get_or_init<F>(&self, f: F) -> NonZeroUsize
31+
where
32+
F: FnOnce() -> NonZeroUsize,
33+
{
34+
enum Void {}
35+
match self.get_or_try_init(|| Ok::<NonZeroUsize, Void>(f())) {
36+
Ok(val) => val,
37+
Err(void) => match void {},
38+
}
39+
}
40+
41+
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<NonZeroUsize, E>
42+
where
43+
F: FnOnce() -> Result<NonZeroUsize, E>,
44+
{
45+
let val = self.inner.load(Ordering::Acquire);
46+
let res = match NonZeroUsize::new(val) {
47+
Some(it) => it,
48+
None => {
49+
let mut val = f()?.get();
50+
let old_val = self.inner.compare_and_swap(0, val, Ordering::AcqRel);
51+
if old_val != 0 {
52+
val = old_val;
53+
}
54+
unsafe { NonZeroUsize::new_unchecked(val) }
55+
}
56+
};
57+
Ok(res)
58+
}
59+
}
60+
61+
#[derive(Default, Debug)]
62+
pub struct OnceBool {
63+
inner: OnceNonZeroUsize,
64+
}
65+
66+
impl OnceBool {
67+
fn from_usize(value: NonZeroUsize) -> bool {
68+
value.get() == 1
69+
}
70+
fn to_usize(value: bool) -> NonZeroUsize {
71+
unsafe { NonZeroUsize::new_unchecked(if value { 1 } else { 2 }) }
72+
}
73+
74+
pub const fn new() -> OnceBool {
75+
OnceBool { inner: OnceNonZeroUsize::new() }
76+
}
77+
78+
pub fn get(&self) -> Option<bool> {
79+
self.inner.get().map(OnceBool::from_usize)
80+
}
81+
82+
pub fn set(&self, value: bool) -> Result<(), ()> {
83+
self.inner.set(OnceBool::to_usize(value))
84+
}
85+
86+
pub fn get_or_init<F>(&self, f: F) -> bool
87+
where
88+
F: FnOnce() -> bool,
89+
{
90+
OnceBool::from_usize(self.inner.get_or_init(|| OnceBool::to_usize(f())))
91+
}
92+
93+
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<bool, E>
94+
where
95+
F: FnOnce() -> Result<bool, E>,
96+
{
97+
self.inner.get_or_try_init(|| f().map(OnceBool::to_usize)).map(OnceBool::from_usize)
98+
}
99+
}
100+
101+
#[cfg(feature = "alloc")]
102+
pub use self::once_box::OnceBox;
103+
#[cfg(feature = "alloc")]
104+
mod once_box {
105+
use alloc::boxed::Box;
106+
use core::{
107+
marker::PhantomData,
108+
ptr,
109+
sync::atomic::{AtomicPtr, Ordering},
110+
};
111+
112+
#[derive(Default, Debug)]
113+
pub struct OnceBox<T> {
114+
inner: AtomicPtr<T>,
115+
ghost: PhantomData<Option<Box<T>>>,
116+
}
117+
118+
impl<T> Drop for OnceBox<T> {
119+
fn drop(&mut self) {
120+
let ptr = *self.inner.get_mut();
121+
if !ptr.is_null() {
122+
drop(unsafe { Box::from_raw(ptr) })
123+
}
124+
}
125+
}
126+
127+
impl<T> OnceBox<T> {
128+
pub const fn new() -> OnceBox<T> {
129+
OnceBox { inner: AtomicPtr::new(ptr::null_mut()), ghost: PhantomData }
130+
}
131+
132+
pub fn get(&self) -> Option<&T> {
133+
let ptr = self.inner.load(Ordering::Acquire);
134+
if ptr.is_null() {
135+
return None;
136+
}
137+
Some(unsafe { &*ptr })
138+
}
139+
140+
// Result<(), Box<T>> here?
141+
pub fn set(&self, value: T) -> Result<(), ()> {
142+
let ptr = Box::into_raw(Box::new(value));
143+
if ptr.is_null() {
144+
drop(unsafe { Box::from_raw(ptr) });
145+
return Err(());
146+
}
147+
Ok(())
148+
}
149+
150+
pub fn get_or_init<F>(&self, f: F) -> &T
151+
where
152+
F: FnOnce() -> T,
153+
{
154+
enum Void {}
155+
match self.get_or_try_init(|| Ok::<T, Void>(f())) {
156+
Ok(val) => val,
157+
Err(void) => match void {},
158+
}
159+
}
160+
161+
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
162+
where
163+
F: FnOnce() -> Result<T, E>,
164+
{
165+
let mut ptr = self.inner.load(Ordering::Acquire);
166+
167+
if ptr.is_null() {
168+
let val = f()?;
169+
ptr = Box::into_raw(Box::new(val));
170+
let old_ptr = self.inner.compare_and_swap(ptr::null_mut(), ptr, Ordering::AcqRel);
171+
if !old_ptr.is_null() {
172+
drop(unsafe { Box::from_raw(ptr) });
173+
ptr = old_ptr;
174+
}
175+
};
176+
Ok(unsafe { &*ptr })
177+
}
178+
}
179+
180+
/// ```compile_fail
181+
/// struct S(*mut ());
182+
/// unsafe impl Sync for S {}
183+
///
184+
/// fn share<T: Sync>(_: &T) {}
185+
/// share(&once_cell::race::OnceBox::<S>::new());
186+
/// ```
187+
unsafe impl<T: Sync + Send> Sync for OnceBox<T> {}
188+
}

0 commit comments

Comments
 (0)