once_self_cell/
lib.rs

1use once_cell::sync::OnceCell as Sync_OnceCell;
2use once_cell::unsync::OnceCell as Unsync_OnceCell;
3
4use crate::unsafe_once_self_cell::DependentInner;
5
6pub mod unsafe_once_self_cell;
7
8pub trait OnceCellCompatible<T> {
9    fn new() -> Self;
10    fn get(&self) -> Option<&T>;
11    fn get_or_init<F>(&self, f: F) -> &T
12    where
13        F: FnOnce() -> T;
14    fn take(&mut self) -> Option<T>;
15}
16
17// HKT sigh.
18
19#[derive(Debug)]
20pub struct UnsyncOnceCell(Unsync_OnceCell<DependentInner>);
21
22impl crate::OnceCellCompatible<DependentInner> for UnsyncOnceCell {
23    fn new() -> Self {
24        UnsyncOnceCell(Unsync_OnceCell::new())
25    }
26    fn get(&self) -> Option<&DependentInner> {
27        self.0.get()
28    }
29    fn get_or_init<F>(&self, f: F) -> &DependentInner
30    where
31        F: FnOnce() -> DependentInner,
32    {
33        self.0.get_or_init(f)
34    }
35    fn take(&mut self) -> Option<DependentInner> {
36        self.0.take()
37    }
38}
39
40#[macro_export]
41macro_rules! unsync_once_self_cell {
42    ($StructName:ident, $Owner:ty, $Dependent:ty $(, $StructMeta:meta)* $(,)?) => {
43        $(#[$StructMeta])*
44        struct $StructName {
45            unsafe_self_cell: ::once_self_cell::unsafe_once_self_cell::UnsafeOnceSelfCell<
46                $Owner,
47                ::once_self_cell::UnsyncOnceCell,
48            >,
49        }
50
51        impl $StructName {
52            pub fn new(owner: $Owner) -> Self {
53                Self {
54                    unsafe_self_cell: unsafe {
55                        ::once_self_cell::unsafe_once_self_cell::UnsafeOnceSelfCell::new(owner)
56                    },
57                }
58            }
59
60            pub fn get_owner<'a>(&'a self) -> &'a $Owner {
61                unsafe { self.unsafe_self_cell.get_owner() }
62            }
63
64            pub fn get_or_init_dependent<'a>(&'a self) -> &'a $Dependent {
65                unsafe {
66                    self.unsafe_self_cell
67                        .get_or_init_dependent(|owner_ref| owner_ref.into())
68                }
69            }
70
71            pub fn dependent_is_none(&self) -> bool {
72                self.unsafe_self_cell.dependent_is_none()
73            }
74        }
75
76        impl Drop for $StructName {
77            fn drop(&mut self) {
78                unsafe {
79                    self.unsafe_self_cell.drop_dependent::<$Dependent>();
80                }
81            }
82        }
83    };
84}
85
86#[derive(Debug)]
87pub struct SyncOnceCell(Sync_OnceCell<DependentInner>);
88
89impl crate::OnceCellCompatible<DependentInner> for SyncOnceCell {
90    fn new() -> Self {
91        SyncOnceCell(Sync_OnceCell::new())
92    }
93    fn get(&self) -> Option<&DependentInner> {
94        self.0.get()
95    }
96    fn get_or_init<F>(&self, f: F) -> &DependentInner
97    where
98        F: FnOnce() -> DependentInner,
99    {
100        self.0.get_or_init(f)
101    }
102    fn take(&mut self) -> Option<DependentInner> {
103        self.0.take()
104    }
105}
106
107// A mutable pointer that only gets changed in 2 ways:
108//
109// 1.
110// get_or_init, sync::OnceCell takes care of establishing a happens-before
111// relationship between a potential write and read of the lazy init.
112//
113// 2.
114// drop_dependent_unconditional, might overwrite the OnceCell with it's
115// default empty state. This hinges on OnceCell::take pulling out the
116// value only exactly once even if called concurrently. Which is given,
117// because the Rust type system ensures only exactly one &mut can exist
118// at any time. And a &mut is required for calling drop_dependent_unconditional.
119unsafe impl Send for SyncOnceCell {}
120unsafe impl Sync for SyncOnceCell {}
121
122#[macro_export]
123macro_rules! sync_once_self_cell {
124    ($StructName:ident, $Owner:ty, $Dependent:ty $(, $StructMeta:meta)* $(,)?) => {
125        $(#[$StructMeta])*
126        struct $StructName {
127            unsafe_self_cell: ::once_self_cell::unsafe_once_self_cell::UnsafeOnceSelfCell<
128                $Owner,
129                ::once_self_cell::SyncOnceCell,
130            >,
131        }
132
133        impl $StructName {
134            pub fn new(owner: $Owner) -> Self {
135                Self {
136                    unsafe_self_cell: unsafe {
137                        ::once_self_cell::unsafe_once_self_cell::UnsafeOnceSelfCell::new(owner)
138                    },
139                }
140            }
141
142            pub fn get_owner<'a>(&'a self) -> &'a $Owner {
143                unsafe { self.unsafe_self_cell.get_owner() }
144            }
145
146            pub fn get_or_init_dependent<'a>(&'a self) -> &'a $Dependent {
147                unsafe {
148                    self.unsafe_self_cell
149                        .get_or_init_dependent(|owner_ref| owner_ref.into())
150                }
151            }
152
153            pub fn dependent_is_none(&self) -> bool {
154                self.unsafe_self_cell.dependent_is_none()
155            }
156        }
157
158        impl Drop for $StructName {
159            fn drop(&mut self) {
160                unsafe {
161                    self.unsafe_self_cell.drop_dependent::<$Dependent>();
162                }
163            }
164        }
165    };
166}
167
168// pub mod custom {
169//     // User provided OnceCell. Has to implement OnceCellCompatible.
170//     pub type OnceSelfCell<Owner, DependentStaticLifetime, DependentCell> =
171//         crate::once_self_cell::OnceSelfCell<Owner, DependentStaticLifetime, DependentCell>;
172// }