1#![deny(clippy::all)]
2#![deny(clippy::assertions_on_result_states)]
3#![deny(clippy::match_wild_err_arm)]
4#![deny(clippy::allow_attributes_without_reason)]
5#![warn(clippy::pedantic)]
6#![warn(clippy::nursery)]
7#![warn(clippy::cargo)]
8#![allow(
9 clippy::missing_const_for_fn,
10 reason = "Since we cannot make a constant function non-constant after its release,
11 we need to look for a reason to make it constant, and not vice versa."
12)]
13#![allow(
14 clippy::must_use_candidate,
15 reason = "It is better to developer think about it."
16)]
17#![allow(
18 clippy::missing_errors_doc,
19 reason = "Unless the error is something special,
20 the developer should document it."
21)]
22
23use std::ops::{Deref, DerefMut};
24#[cfg(debug_assertions)]
25use std::sync::atomic::{AtomicBool, Ordering};
26#[cfg(debug_assertions)]
27use std::sync::Arc;
28
29pub struct ManuallyStatic<T> {
40 value: T,
41 #[cfg(debug_assertions)]
44 was_dropped: Arc<AtomicBool>,
45}
46
47impl<T> ManuallyStatic<T> {
48 pub fn new(value: T) -> Self {
50 Self {
51 value,
52 #[cfg(debug_assertions)]
53 was_dropped: Arc::new(AtomicBool::new(false)),
54 }
55 }
56
57 pub fn get_ref(&self) -> ManuallyStaticRef<T> {
61 ManuallyStaticRef {
62 value_ref: &self.value,
63 #[cfg(debug_assertions)]
64 was_dropped: self.was_dropped.clone(),
65 }
66 }
67
68 pub fn get_mut(&mut self) -> ManuallyStaticRefMut<T> {
72 ManuallyStaticRefMut {
73 value_ref_mut: &mut self.value,
74 #[cfg(debug_assertions)]
75 was_dropped: self.was_dropped.clone(),
76 }
77 }
78}
79
80#[cfg(debug_assertions)]
83impl<T> Drop for ManuallyStatic<T> {
84 fn drop(&mut self) {
85 self.was_dropped.store(true, Ordering::Release);
86 }
87}
88
89pub struct ManuallyStaticRef<T> {
93 value_ref: *const T,
94 #[cfg(debug_assertions)]
95 was_dropped: Arc<AtomicBool>,
96}
97
98impl<T> Deref for ManuallyStaticRef<T> {
99 type Target = T;
100
101 fn deref(&self) -> &T {
102 #[cfg(debug_assertions)]
103 {
104 assert!(
105 !self.was_dropped.load(Ordering::Acquire),
106 "ManuallyStaticRef: Attempted to dereference value after ManuallyStatic was dropped!"
107 );
108 }
109
110 unsafe { &*self.value_ref }
111 }
112}
113
114pub struct ManuallyStaticRefMut<T> {
118 value_ref_mut: *mut T,
119 #[cfg(debug_assertions)]
120 was_dropped: Arc<AtomicBool>,
121}
122
123impl<T> Deref for ManuallyStaticRefMut<T> {
124 type Target = T;
125
126 fn deref(&self) -> &T {
127 #[cfg(debug_assertions)]
128 {
129 assert!(
130 !self.was_dropped.load(Ordering::Acquire),
131 "ManuallyStaticRefMut: Attempted to dereference value after ManuallyStatic was dropped!"
132 );
133 }
134
135 unsafe { &*self.value_ref_mut }
136 }
137}
138
139impl<T> DerefMut for ManuallyStaticRefMut<T> {
140 fn deref_mut(&mut self) -> &mut T {
141 #[cfg(debug_assertions)]
142 {
143 assert!(
144 !self.was_dropped.load(Ordering::Acquire),
145 "ManuallyStaticRefMut: Attempted to dereference value after ManuallyStatic was dropped!"
146 );
147 }
148
149 unsafe { &mut *self.value_ref_mut }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_manually_static_ref_access() {
159 let ms = ManuallyStatic::new(42);
160 let ms_ref = ms.get_ref();
161
162 assert_eq!(*ms_ref, 42);
163 }
164
165 #[test]
166 fn test_manually_static_ref_mut_access() {
167 let mut ms = ManuallyStatic::new(42);
168 let mut ms_mut = ms.get_mut();
169
170 *ms_mut = 100;
171
172 assert_eq!(*ms_mut, 100);
173 assert_eq!(*ms.get_ref(), 100);
174 }
175
176 #[test]
177 #[cfg(debug_assertions)] #[should_panic(expected = "Attempted to dereference value after ManuallyStatic was dropped!")]
179 fn test_manually_static_ref_panics_on_drop() {
180 let ms_ref;
181
182 {
183 let ms = ManuallyStatic::new(42);
184
185 ms_ref = ms.get_ref();
186 }
187
188 let _ = *ms_ref;
189 }
190
191 #[test]
192 #[cfg(debug_assertions)] #[should_panic(expected = "Attempted to dereference value after ManuallyStatic was dropped!")]
194 fn test_manually_static_ref_mut_panics_on_drop() {
195 let ms_mut;
196
197 {
198 let mut ms = ManuallyStatic::new(42);
199
200 ms_mut = ms.get_mut();
201 }
202
203 let _ = *ms_mut;
204 }
205
206 #[test]
207 #[cfg(not(debug_assertions))] fn test_manually_static_ref_no_panic_on_drop_release_mode() {
209 let ms_ptr;
210
211 {
212 let ms = ManuallyStatic::new(42);
213
214 ms_ptr = ms.get_ref();
215 }
216
217 let _ = *ms_ptr;
218 }
219}