1#[doc(hidden)]
2pub use scopeguard;
3
4#[macro_export]
16macro_rules! snarc {
17 ($send:ident, $unsend:ident, $ref:ident $(, $expect:literal)?) => {
18 pub use _snarc_impl::$send;
19 pub use _snarc_impl::$unsend;
20 pub use _snarc_impl::$ref;
21
22 mod _snarc_impl {
23 use std::alloc;
24 use std::ops::Deref;
25 use std::ops::DerefMut;
26 use std::ptr;
27
28 use $crate::Context;
29 use $crate::ErasedNarc;
30 use $crate::ErasedSnarc;
31 use $crate::State;
32
33 thread_local!(static THREAD_LOCAL: std::cell::Cell<State> = Default::default());
34
35 struct SnarcBox<T> {
36 count: std::cell::Cell<usize>,
37 value: T,
38 }
39
40 impl<T> SnarcBox<T> {
41 fn new_ptr(value: T) -> *mut Self {
42 Box::leak(Box::new(Self {
43 count: std::cell::Cell::new(0),
44 value,
45 }))
46 }
47 }
48
49 pub struct $send<T> {
50 ptr: *mut SnarcBox<T>,
51 phantom: std::marker::PhantomData<SnarcBox<T>>,
52 }
53
54 unsafe impl<T: Send> Send for $send<T> {}
55 unsafe impl<T: Sync> Sync for $send<T> {}
56
57 impl<T> $send<T> {
58 #[doc = stringify!($send)]
60 pub fn new(value: T) -> Self {
62 Self {
63 ptr: SnarcBox::new_ptr(value),
64 phantom: std::marker::PhantomData,
65 }
66 }
67
68 #[doc = stringify!($send)]
70 #[doc = stringify!($unsend)]
72 pub fn into_unsend(mut self) -> $unsend<T> {
74 let narc = $unsend {
75 ptr: self.ptr,
76 phantom: self.phantom,
77 };
78
79 self.ptr = ptr::null_mut();
80
81 narc
82 }
83
84 #[doc = stringify!($send)]
86 pub fn into_erased(self) -> ErasedSnarc
88 where
89 T: Send + 'static,
90 {
91 let snarc: Box<dyn Context + Send + 'static> = Box::new(self);
92 ErasedSnarc::from(snarc)
93 }
94
95 #[inline(always)]
96 fn inner(&self) -> &SnarcBox<T> {
97 unsafe { &*self.ptr }
98 }
99
100 #[inline]
101 unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
102 &mut (*this.ptr).value
103 }
104
105 pub fn new_ref(&self) -> $ref<T> {
107 let inner = self.inner();
108
109 inner.count.set(inner.count.get() + 1);
110
111 $ref {
112 ptr: self.ptr,
113 phantom: Default::default(),
114 }
115 }
116
117 pub fn enter<F, R>(&mut self, f: F) -> R
120 where
121 F: FnOnce(&T) -> R,
122 {
123 THREAD_LOCAL.with(|c| {
124 if c.get() == State::Entered {
125 panic!(concat!(
126 "Another ",
127 stringify!($send),
128 " is already entered."
129 ))
130 }
131
132 c.set(State::Entered);
133 });
134
135 let _guard = $crate::scopeguard::guard((), |_| {
136 THREAD_LOCAL.with(|c| c.set(State::Default));
137 });
138
139 f(&self.inner().value)
140 }
141 }
142
143 impl<T: Send + 'static> From<$send<T>> for ErasedSnarc {
144 fn from(snarc: $send<T>) -> Self {
145 snarc.into_erased()
146 }
147 }
148
149 impl<T: Send + 'static> From<$send<T>> for ErasedNarc {
150 fn from(snarc: $send<T>) -> Self {
151 snarc.into_unsend().into_erased()
152 }
153 }
154
155 impl<T> Context for $send<T> {
156 fn set(&mut self, v: State) {
157 THREAD_LOCAL.with(|c| {
158 if v == State::Entered && c.get() == State::Entered {
159 panic!(concat!(
160 "Another ",
161 stringify!($send),
162 " is already entered."
163 ))
164 }
165
166 c.set(v);
167 });
168 }
169 }
170
171 impl<T> Deref for $send<T> {
172 type Target = T;
173
174 #[inline(always)]
175 fn deref(&self) -> &Self::Target {
176 &self.inner().value
177 }
178 }
179
180 impl<T> DerefMut for $send<T> {
181 #[inline(always)]
182 fn deref_mut(&mut self) -> &mut Self::Target {
183 unsafe { Self::get_mut_unchecked(self) }
184 }
185 }
186
187 impl<T> Drop for $send<T> {
188 fn drop(&mut self) {
189 if !self.ptr.is_null() {
190 THREAD_LOCAL.with(|c| {
191 if c.get() == State::Entered {
192 panic!(concat!(
193 "Another ",
194 stringify!($send),
195 " is already entered."
196 ))
197 }
198
199 c.set(State::Entered)
200 });
201
202 let _guard = $crate::scopeguard::guard((), |_| {
203 THREAD_LOCAL.with(|c| c.set(State::Default));
204 });
205
206 unsafe {
207 ptr::drop_in_place(Self::get_mut_unchecked(self));
209 }
210
211 if self.inner().count.get() == 0 {
212 unsafe {
213 ptr::addr_of_mut!((*self.ptr).count).drop_in_place();
214 let layout = alloc::Layout::for_value(&*self.ptr);
215 alloc::dealloc(self.ptr.cast(), layout);
216 }
217 }
218 }
219 }
220 }
221
222 #[doc = stringify!($unsend)]
226 #[doc = stringify!($send)]
228 pub struct $unsend<T> {
231 ptr: *mut SnarcBox<T>,
232 phantom: std::marker::PhantomData<SnarcBox<T>>,
233 }
234
235 unsafe impl<T: Sync> Sync for $unsend<T> {}
236
237 impl<T> $unsend<T> {
238 #[doc = stringify!($unsend)]
240 pub fn new(value: T) -> Self {
242 Self {
243 ptr: SnarcBox::new_ptr(value),
244 phantom: std::marker::PhantomData,
245 }
246 }
247
248 #[doc = stringify!($unsend)]
250 #[doc = stringify!($send)]
252 pub fn into_send(mut self) -> $send<T> {
254 let snarc = $send {
255 ptr: self.ptr,
256 phantom: self.phantom,
257 };
258
259 self.ptr = ptr::null_mut();
260
261 snarc
262 }
263
264 #[doc = stringify!($unsend)]
266 pub fn into_erased(self) -> ErasedNarc
268 where
269 T: Send + 'static,
270 {
271 self.into_send().into_erased().into_unsend()
272 }
273
274 #[inline(always)]
275 fn inner(&self) -> &SnarcBox<T> {
276 unsafe { &*self.ptr }
277 }
278
279 #[inline]
280 unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
281 &mut (*this.ptr).value
282 }
283
284 pub fn new_ref(&self) -> $ref<T> {
286 let inner = self.inner();
287
288 inner.count.set(inner.count.get() + 1);
289
290 $ref {
291 ptr: self.ptr,
292 phantom: Default::default(),
293 }
294 }
295 }
296
297 impl<T: Send + 'static> From<$unsend<T>> for ErasedSnarc {
298 fn from(narc: $unsend<T>) -> Self {
299 narc.into_send().into_erased()
300 }
301 }
302
303 impl<T: Send + 'static> From<$unsend<T>> for ErasedNarc {
304 fn from(narc: $unsend<T>) -> Self {
305 narc.into_erased()
306 }
307 }
308
309 impl<T> Deref for $unsend<T> {
310 type Target = T;
311
312 #[inline(always)]
313 fn deref(&self) -> &Self::Target {
314 &self.inner().value
315 }
316 }
317
318 impl<T> DerefMut for $unsend<T> {
319 #[inline(always)]
320 fn deref_mut(&mut self) -> &mut Self::Target {
321 unsafe { Self::get_mut_unchecked(self) }
322 }
323 }
324
325 impl<T> Drop for $unsend<T> {
326 fn drop(&mut self) {
327 if !self.ptr.is_null() {
328 THREAD_LOCAL.with(|c| {
329 if c.get() == State::Entered {
330 panic!(concat!(
331 "Another ",
332 stringify!($send),
333 " is already entered."
334 ))
335 }
336
337 c.set(State::Entered)
338 });
339
340 let _guard = $crate::scopeguard::guard((), |_| {
341 THREAD_LOCAL.with(|c| c.set(State::Default));
342 });
343
344 unsafe {
345 ptr::drop_in_place(Self::get_mut_unchecked(self));
347 }
348
349 if self.inner().count.get() == 0 {
350 unsafe {
351 ptr::addr_of_mut!((*self.ptr).count).drop_in_place();
352 let layout = alloc::Layout::for_value(&*self.ptr);
353 alloc::dealloc(self.ptr.cast(), layout);
354 }
355 }
356 }
357 }
358 }
359
360 pub struct $ref<T> {
361 ptr: *mut SnarcBox<T>,
362 phantom: std::marker::PhantomData<SnarcBox<T>>,
363 }
364
365 unsafe impl<T> Send for $ref<T> {}
366 unsafe impl<T> Sync for $ref<T> {}
367
368 impl<T> $ref<T> {
369 #[inline(always)]
370 fn inner(&self) -> &SnarcBox<T> {
371 unsafe { &*self.ptr }
372 }
373
374 pub fn get(&self) -> Option<&T> {
375 let inner = self.inner();
376
377 if THREAD_LOCAL.with(|c| c.get().is_set()) {
378 Some(&inner.value)
379 } else {
380 None
381 }
382 }
383
384 $(
385 pub fn expect(&self) -> &T {
386 self.get().expect($expect)
387 }
388 )?
389 }
390
391 impl<T> Clone for $ref<T> {
392 fn clone(&self) -> Self {
393 if THREAD_LOCAL.with(|c| c.get().is_set()) {
394 let inner = self.inner();
395
396 inner.count.set(inner.count.get() + 1);
397
398 Self {
399 ptr: self.ptr,
400 phantom: Default::default(),
401 }
402 } else {
403 panic!(concat!(
404 stringify!($ref),
405 "::clone() outside of ",
406 stringify!($send),
407 "::enter(…)"
408 ))
409 }
410 }
411 }
412
413 impl<T> Drop for $ref<T> {
414 fn drop(&mut self) {
415 if THREAD_LOCAL.with(|c| c.get().is_set()) {
416 let inner = self.inner();
417
418 inner.count.set(inner.count.get() - 1);
419 } else {
420 #[cfg(debug_assertions)]
421 panic!(concat!(
422 stringify!($ref),
423 "::drop() outside of ",
424 stringify!($send),
425 "::enter(…)"
426 ))
427 }
428 }
429 }
430 }
431 };
432}
433
434#[cfg(test)]
435mod tests {
436 crate::snarc!(Snarc, Narc, SnarcRef, "expectation");
437
438 crate::tests::tests!(Snarc, Narc, SnarcRef);
439}