|  | 
| 1 | 1 | use super::UnsafeCell; | 
|  | 2 | +use crate::hint::unreachable_unchecked; | 
| 2 | 3 | use crate::ops::Deref; | 
| 3 | 4 | use crate::{fmt, mem}; | 
| 4 | 5 | 
 | 
| @@ -82,7 +83,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> { | 
| 82 | 83 |         match this.state.into_inner() { | 
| 83 | 84 |             State::Init(data) => Ok(data), | 
| 84 | 85 |             State::Uninit(f) => Err(f), | 
| 85 |  | -            State::Poisoned => panic!("LazyCell instance has previously been poisoned"), | 
|  | 86 | +            State::Poisoned => panic_poisoned(), | 
| 86 | 87 |         } | 
| 87 | 88 |     } | 
| 88 | 89 | 
 | 
| @@ -114,7 +115,72 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> { | 
| 114 | 115 |             State::Init(data) => data, | 
| 115 | 116 |             // SAFETY: The state is uninitialized. | 
| 116 | 117 |             State::Uninit(_) => unsafe { LazyCell::really_init(this) }, | 
| 117 |  | -            State::Poisoned => panic!("LazyCell has previously been poisoned"), | 
|  | 118 | +            State::Poisoned => panic_poisoned(), | 
|  | 119 | +        } | 
|  | 120 | +    } | 
|  | 121 | + | 
|  | 122 | +    /// Forces the evaluation of this lazy value and returns a mutable reference to | 
|  | 123 | +    /// the result. | 
|  | 124 | +    /// | 
|  | 125 | +    /// # Examples | 
|  | 126 | +    /// | 
|  | 127 | +    /// ``` | 
|  | 128 | +    /// #![feature(lazy_get)] | 
|  | 129 | +    /// use std::cell::LazyCell; | 
|  | 130 | +    /// | 
|  | 131 | +    /// let mut lazy = LazyCell::new(|| 92); | 
|  | 132 | +    /// | 
|  | 133 | +    /// let p = LazyCell::force_mut(&mut lazy); | 
|  | 134 | +    /// assert_eq!(*p, 92); | 
|  | 135 | +    /// *p = 44; | 
|  | 136 | +    /// assert_eq!(*lazy, 44); | 
|  | 137 | +    /// ``` | 
|  | 138 | +    #[inline] | 
|  | 139 | +    #[unstable(feature = "lazy_get", issue = "129333")] | 
|  | 140 | +    pub fn force_mut(this: &mut LazyCell<T, F>) -> &mut T { | 
|  | 141 | +        #[cold] | 
|  | 142 | +        /// # Safety | 
|  | 143 | +        /// May only be called when the state is `Uninit`. | 
|  | 144 | +        unsafe fn really_init_mut<T, F: FnOnce() -> T>(state: &mut State<T, F>) -> &mut T { | 
|  | 145 | +            // INVARIANT: Always valid, but the value may not be dropped. | 
|  | 146 | +            struct PoisonOnPanic<T, F>(*mut State<T, F>); | 
|  | 147 | +            impl<T, F> Drop for PoisonOnPanic<T, F> { | 
|  | 148 | +                #[inline] | 
|  | 149 | +                fn drop(&mut self) { | 
|  | 150 | +                    // SAFETY: Invariant states it is valid, and we don't drop the old value. | 
|  | 151 | +                    unsafe { | 
|  | 152 | +                        self.0.write(State::Poisoned); | 
|  | 153 | +                    } | 
|  | 154 | +                } | 
|  | 155 | +            } | 
|  | 156 | + | 
|  | 157 | +            let State::Uninit(f) = state else { | 
|  | 158 | +                // `unreachable!()` here won't optimize out because the function is cold. | 
|  | 159 | +                // SAFETY: Precondition. | 
|  | 160 | +                unsafe { unreachable_unchecked() }; | 
|  | 161 | +            }; | 
|  | 162 | +            // SAFETY: We never drop the state after we read `f`, and we write a valid value back | 
|  | 163 | +            // in any case, panic or success. `f` can't access the `LazyCell` because it is mutably | 
|  | 164 | +            // borrowed. | 
|  | 165 | +            let f = unsafe { core::ptr::read(f) }; | 
|  | 166 | +            // INVARIANT: Initiated from mutable reference, don't drop because we read it. | 
|  | 167 | +            let guard = PoisonOnPanic(state); | 
|  | 168 | +            let data = f(); | 
|  | 169 | +            // SAFETY: `PoisonOnPanic` invariant, and we don't drop the old value. | 
|  | 170 | +            unsafe { | 
|  | 171 | +                core::ptr::write(guard.0, State::Init(data)); | 
|  | 172 | +            } | 
|  | 173 | +            core::mem::forget(guard); | 
|  | 174 | +            let State::Init(data) = state else { unreachable!() }; | 
|  | 175 | +            data | 
|  | 176 | +        } | 
|  | 177 | + | 
|  | 178 | +        let state = this.state.get_mut(); | 
|  | 179 | +        match state { | 
|  | 180 | +            State::Init(data) => data, | 
|  | 181 | +            // SAFETY: `state` is `Uninit`. | 
|  | 182 | +            State::Uninit(_) => unsafe { really_init_mut(state) }, | 
|  | 183 | +            State::Poisoned => panic_poisoned(), | 
| 118 | 184 |         } | 
| 119 | 185 |     } | 
| 120 | 186 | 
 | 
| @@ -152,13 +218,55 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> { | 
| 152 | 218 | } | 
| 153 | 219 | 
 | 
| 154 | 220 | impl<T, F> LazyCell<T, F> { | 
|  | 221 | +    /// Returns a reference to the value if initialized, or `None` if not. | 
|  | 222 | +    /// | 
|  | 223 | +    /// # Examples | 
|  | 224 | +    /// | 
|  | 225 | +    /// ``` | 
|  | 226 | +    /// #![feature(lazy_get)] | 
|  | 227 | +    /// | 
|  | 228 | +    /// use std::cell::LazyCell; | 
|  | 229 | +    /// | 
|  | 230 | +    /// let mut lazy = LazyCell::new(|| 92); | 
|  | 231 | +    /// | 
|  | 232 | +    /// assert_eq!(LazyCell::get_mut(&mut lazy), None); | 
|  | 233 | +    /// let _ = LazyCell::force(&lazy); | 
|  | 234 | +    /// *LazyCell::get_mut(&mut lazy).unwrap() = 44; | 
|  | 235 | +    /// assert_eq!(*lazy, 44); | 
|  | 236 | +    /// ``` | 
| 155 | 237 |     #[inline] | 
| 156 |  | -    fn get(&self) -> Option<&T> { | 
|  | 238 | +    #[unstable(feature = "lazy_get", issue = "129333")] | 
|  | 239 | +    pub fn get_mut(this: &mut LazyCell<T, F>) -> Option<&mut T> { | 
|  | 240 | +        let state = this.state.get_mut(); | 
|  | 241 | +        match state { | 
|  | 242 | +            State::Init(data) => Some(data), | 
|  | 243 | +            _ => None, | 
|  | 244 | +        } | 
|  | 245 | +    } | 
|  | 246 | + | 
|  | 247 | +    /// Returns a mutable reference to the value if initialized, or `None` if not. | 
|  | 248 | +    /// | 
|  | 249 | +    /// # Examples | 
|  | 250 | +    /// | 
|  | 251 | +    /// ``` | 
|  | 252 | +    /// #![feature(lazy_get)] | 
|  | 253 | +    /// | 
|  | 254 | +    /// use std::cell::LazyCell; | 
|  | 255 | +    /// | 
|  | 256 | +    /// let lazy = LazyCell::new(|| 92); | 
|  | 257 | +    /// | 
|  | 258 | +    /// assert_eq!(LazyCell::get(&lazy), None); | 
|  | 259 | +    /// let _ = LazyCell::force(&lazy); | 
|  | 260 | +    /// assert_eq!(LazyCell::get(&lazy), Some(&92)); | 
|  | 261 | +    /// ``` | 
|  | 262 | +    #[inline] | 
|  | 263 | +    #[unstable(feature = "lazy_get", issue = "129333")] | 
|  | 264 | +    pub fn get(this: &LazyCell<T, F>) -> Option<&T> { | 
| 157 | 265 |         // SAFETY: | 
| 158 | 266 |         // This is sound for the same reason as in `force`: once the state is | 
| 159 | 267 |         // initialized, it will not be mutably accessed again, so this reference | 
| 160 | 268 |         // will stay valid for the duration of the borrow to `self`. | 
| 161 |  | -        let state = unsafe { &*self.state.get() }; | 
|  | 269 | +        let state = unsafe { &*this.state.get() }; | 
| 162 | 270 |         match state { | 
| 163 | 271 |             State::Init(data) => Some(data), | 
| 164 | 272 |             _ => None, | 
| @@ -188,10 +296,16 @@ impl<T: Default> Default for LazyCell<T> { | 
| 188 | 296 | impl<T: fmt::Debug, F> fmt::Debug for LazyCell<T, F> { | 
| 189 | 297 |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
| 190 | 298 |         let mut d = f.debug_tuple("LazyCell"); | 
| 191 |  | -        match self.get() { | 
|  | 299 | +        match LazyCell::get(self) { | 
| 192 | 300 |             Some(data) => d.field(data), | 
| 193 | 301 |             None => d.field(&format_args!("<uninit>")), | 
| 194 | 302 |         }; | 
| 195 | 303 |         d.finish() | 
| 196 | 304 |     } | 
| 197 | 305 | } | 
|  | 306 | + | 
|  | 307 | +#[cold] | 
|  | 308 | +#[inline(never)] | 
|  | 309 | +fn panic_poisoned() -> ! { | 
|  | 310 | +    panic!("LazyCell instance has previously been poisoned") | 
|  | 311 | +} | 
0 commit comments