1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use once_cell::sync::OnceCell as Sync_OnceCell;
use once_cell::unsync::OnceCell as Unsync_OnceCell;

use crate::unsafe_once_self_cell::DependentInner;

pub mod unsafe_once_self_cell;

pub trait OnceCellCompatible<T> {
    fn new() -> Self;
    fn get(&self) -> Option<&T>;
    fn get_or_init<F>(&self, f: F) -> &T
    where
        F: FnOnce() -> T;
    fn take(&mut self) -> Option<T>;
}

// HKT sigh.

#[derive(Debug)]
pub struct UnsyncOnceCell(Unsync_OnceCell<DependentInner>);

impl crate::OnceCellCompatible<DependentInner> for UnsyncOnceCell {
    fn new() -> Self {
        UnsyncOnceCell(Unsync_OnceCell::new())
    }
    fn get(&self) -> Option<&DependentInner> {
        self.0.get()
    }
    fn get_or_init<F>(&self, f: F) -> &DependentInner
    where
        F: FnOnce() -> DependentInner,
    {
        self.0.get_or_init(f)
    }
    fn take(&mut self) -> Option<DependentInner> {
        self.0.take()
    }
}

#[macro_export]
macro_rules! unsync_once_self_cell {
    ($StructName:ident, $Owner:ty, $Dependent:ty $(, $StructMeta:meta)* $(,)?) => {
        $(#[$StructMeta])*
        struct $StructName {
            unsafe_self_cell: ::once_self_cell::unsafe_once_self_cell::UnsafeOnceSelfCell<
                $Owner,
                ::once_self_cell::UnsyncOnceCell,
            >,
        }

        impl $StructName {
            pub fn new(owner: $Owner) -> Self {
                Self {
                    unsafe_self_cell: unsafe {
                        ::once_self_cell::unsafe_once_self_cell::UnsafeOnceSelfCell::new(owner)
                    },
                }
            }

            pub fn get_owner<'a>(&'a self) -> &'a $Owner {
                unsafe { self.unsafe_self_cell.get_owner() }
            }

            pub fn get_or_init_dependent<'a>(&'a self) -> &'a $Dependent {
                unsafe {
                    self.unsafe_self_cell
                        .get_or_init_dependent(|owner_ref| owner_ref.into())
                }
            }

            pub fn dependent_is_none(&self) -> bool {
                self.unsafe_self_cell.dependent_is_none()
            }
        }

        impl Drop for $StructName {
            fn drop(&mut self) {
                unsafe {
                    self.unsafe_self_cell.drop_dependent::<$Dependent>();
                }
            }
        }
    };
}

#[derive(Debug)]
pub struct SyncOnceCell(Sync_OnceCell<DependentInner>);

impl crate::OnceCellCompatible<DependentInner> for SyncOnceCell {
    fn new() -> Self {
        SyncOnceCell(Sync_OnceCell::new())
    }
    fn get(&self) -> Option<&DependentInner> {
        self.0.get()
    }
    fn get_or_init<F>(&self, f: F) -> &DependentInner
    where
        F: FnOnce() -> DependentInner,
    {
        self.0.get_or_init(f)
    }
    fn take(&mut self) -> Option<DependentInner> {
        self.0.take()
    }
}

// A mutable pointer that only gets changed in 2 ways:
//
// 1.
// get_or_init, sync::OnceCell takes care of establishing a happens-before
// relationship between a potential write and read of the lazy init.
//
// 2.
// drop_dependent_unconditional, might overwrite the OnceCell with it's
// default empty state. This hinges on OnceCell::take pulling out the
// value only exactly once even if called concurrently. Which is given,
// because the Rust type system ensures only exactly one &mut can exist
// at any time. And a &mut is required for calling drop_dependent_unconditional.
unsafe impl Send for SyncOnceCell {}
unsafe impl Sync for SyncOnceCell {}

#[macro_export]
macro_rules! sync_once_self_cell {
    ($StructName:ident, $Owner:ty, $Dependent:ty $(, $StructMeta:meta)* $(,)?) => {
        $(#[$StructMeta])*
        struct $StructName {
            unsafe_self_cell: ::once_self_cell::unsafe_once_self_cell::UnsafeOnceSelfCell<
                $Owner,
                ::once_self_cell::SyncOnceCell,
            >,
        }

        impl $StructName {
            pub fn new(owner: $Owner) -> Self {
                Self {
                    unsafe_self_cell: unsafe {
                        ::once_self_cell::unsafe_once_self_cell::UnsafeOnceSelfCell::new(owner)
                    },
                }
            }

            pub fn get_owner<'a>(&'a self) -> &'a $Owner {
                unsafe { self.unsafe_self_cell.get_owner() }
            }

            pub fn get_or_init_dependent<'a>(&'a self) -> &'a $Dependent {
                unsafe {
                    self.unsafe_self_cell
                        .get_or_init_dependent(|owner_ref| owner_ref.into())
                }
            }

            pub fn dependent_is_none(&self) -> bool {
                self.unsafe_self_cell.dependent_is_none()
            }
        }

        impl Drop for $StructName {
            fn drop(&mut self) {
                unsafe {
                    self.unsafe_self_cell.drop_dependent::<$Dependent>();
                }
            }
        }
    };
}

// pub mod custom {
//     // User provided OnceCell. Has to implement OnceCellCompatible.
//     pub type OnceSelfCell<Owner, DependentStaticLifetime, DependentCell> =
//         crate::once_self_cell::OnceSelfCell<Owner, DependentStaticLifetime, DependentCell>;
// }