snarc/
default.rs

1#[doc(hidden)]
2pub use scopeguard;
3
4/// Defines three structs, each named by one parameter.
5///
6///  - `$send`, a sendable owning/strong reference,
7///  - `$unsend`, an unsendable owning/strong reference, and
8///  - `$ref`, a sendable weak reference.
9///
10/// Note that this macro declares a `thread_local!` that is is shared by all
11/// instances. That means that instances cannot bind their value to the current
12/// thread at the same time. If this is too restrictive, enable the
13/// `thread-local` feature and use the structs defined in the `thread_local`
14/// module.
15#[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                /// Creates a new `
59                #[doc = stringify!($send)]
60                /// ` with the given inner `value`.
61                pub fn new(value: T) -> Self {
62                    Self {
63                        ptr: SnarcBox::new_ptr(value),
64                        phantom: std::marker::PhantomData,
65                    }
66                }
67
68                /// Turn this `
69                #[doc = stringify!($send)]
70                /// ` into the `!Send` version `
71                #[doc = stringify!($unsend)]
72                /// `.
73                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                /// Turn this parameterized `
85                #[doc = stringify!($send)]
86                /// ` the unparameterized `ErasedSnarc`.
87                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                /// Creates a new non-owning reference to the inner value.
106                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                /// Temporarily bind the inner value to this thread and evaluate `f`
118                /// within that context.
119                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                            // destroy the contained object
208                            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            /// A non-sendable, owning reference-counted pointer to a `T`.
223            ///
224            /// When `
225            #[doc = stringify!($unsend)]
226            /// ` is used exclusively, i.e., never `
227            #[doc = stringify!($send)]
228            /// `, then `Rc` should
229            /// likely be used instead.
230            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                /// Creates a new `
239                #[doc = stringify!($unsend)]
240                /// ` with the given inner `value`.
241                pub fn new(value: T) -> Self {
242                    Self {
243                        ptr: SnarcBox::new_ptr(value),
244                        phantom: std::marker::PhantomData,
245                    }
246                }
247
248                /// Turn this `
249                #[doc = stringify!($unsend)]
250                /// ` into the `Send` version `
251                #[doc = stringify!($send)]
252                /// `.
253                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                /// Turn this parameterized `
265                #[doc = stringify!($unsend)]
266                /// ` the unparameterized `ErasedNarc`.
267                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                /// Creates a new non-owning reference to the inner value.
285                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                            // destroy the contained object
346                            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}