Skip to content

Commit 1911c56

Browse files
Revert "Merge matklad#233"
This reverts commit e3b2260, reversing changes made to 8f39b77.
1 parent e3b2260 commit 1911c56

File tree

2 files changed

+23
-174
lines changed

2 files changed

+23
-174
lines changed

src/lib.rs

Lines changed: 23 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -716,52 +716,15 @@ pub mod unsync {
716716
/// // 92
717717
/// ```
718718
pub struct Lazy<T, F = fn() -> T> {
719-
state: Cell<State>,
720-
data: Data<T, F>,
721-
}
722-
723-
/// Discriminant of the union.
724-
#[derive(Debug, Clone, Copy)]
725-
enum State {
726-
/// `.init` has not been taken yet.
727-
Uninit,
728-
/// `.init` has been *taken*, but the call has not completed (panic?), so there is no `.value` either.
729-
Poisoned,
730-
/// `.value` has been set.
731-
Value,
732-
}
733-
734-
// One of the rare cases `#[repr(C)]` is not needed for an union ("externally tagged `enum`" pattern)
735-
union Data<T, F> {
736-
/// Idea: we don't need *mutation* to dispose of `F`, we can just let it be there, inert, behind a MD.
737-
///
738-
/// This makes it so we remain covariant in `F`.
739-
init: mem::ManuallyDrop<F>,
740-
value: mem::ManuallyDrop<UnsafeCell<T>>,
741-
}
742-
743-
impl<T, F> Drop for Lazy<T, F> {
744-
fn drop(&mut self) {
745-
match self.state.get_mut() {
746-
State::Value => unsafe { mem::ManuallyDrop::drop(&mut self.data.value) },
747-
State::Uninit => unsafe { mem::ManuallyDrop::drop(&mut self.data.init) },
748-
State::Poisoned => {}
749-
}
750-
}
719+
cell: OnceCell<T>,
720+
init: Cell<Option<F>>,
751721
}
752722

753723
impl<T, F: RefUnwindSafe> RefUnwindSafe for Lazy<T, F> where OnceCell<T>: RefUnwindSafe {}
754724

755725
impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
756726
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
757-
match self.state.get() {
758-
// `Lazy("some value")`
759-
State::Value => {
760-
f.debug_tuple("Lazy").field(unsafe { &*self.data.value.get() }).finish()
761-
}
762-
// `Uninit`, or `Poisoned`
763-
state => state.fmt(f),
764-
}
727+
f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish()
765728
}
766729
}
767730

@@ -781,28 +744,18 @@ pub mod unsync {
781744
/// # }
782745
/// ```
783746
pub const fn new(init: F) -> Lazy<T, F> {
784-
Lazy {
785-
state: Cell::new(State::Uninit),
786-
data: Data { init: mem::ManuallyDrop::new(init) },
787-
}
747+
Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) }
788748
}
789749

790750
/// Consumes this `Lazy` returning the stored value.
791751
///
792752
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
793753
pub fn into_value(this: Lazy<T, F>) -> Result<T, F> {
794-
// Safety: beyond the typical "check discriminant before accessing corresponding union variant",
795-
// we have to be careful not to run `this`' `impl Drop` glue as we extract its fields,
796-
// hence the initial extra layer of `ManuallyDrop`.
797-
// Once that's done nothing is owned anymore, so we are free to `ManuallyDrop::take` what we want.
798-
let mut this = mem::ManuallyDrop::new(this);
799-
match this.state.get_mut() {
800-
State::Value => {
801-
Ok(unsafe { mem::ManuallyDrop::take(&mut this.data.value) }.into_inner())
802-
}
803-
State::Uninit => Err(unsafe { mem::ManuallyDrop::take(&mut this.data.init) }),
804-
State::Poisoned => panic!("Lazy instance has previously been poisoned"),
805-
}
754+
let cell = this.cell;
755+
let init = this.init;
756+
cell.into_inner().ok_or_else(|| {
757+
init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
758+
})
806759
}
807760
}
808761

@@ -822,37 +775,10 @@ pub mod unsync {
822775
/// assert_eq!(&*lazy, &92);
823776
/// ```
824777
pub fn force(this: &Lazy<T, F>) -> &T {
825-
match this.state.get() {
826-
State::Value => unsafe { &*this.data.value.get() },
827-
State::Uninit => {
828-
// Safety: `<*const _>::read(&*...)` is the by-ref counterpart of `ManuallyDrop::take`.
829-
// We are allowed to `take` the `F` once we have taken its `State::Uninit` discriminant.
830-
// We cannot put `State::Value` in its stead yet in case `init()` panics.
831-
// Hence the `Poisoned` / "empty `Lazy`" state.
832-
let init = unsafe {
833-
this.state.set(State::Poisoned);
834-
<*const F>::read(&*this.data.init)
835-
};
836-
let value = init();
837-
unsafe {
838-
// Safety: here we need to tread with caution, since we need to "pick a union variant"
839-
// without accidentally asserting that the `ManuallyDrop<... T ...>` is init since it still isn't.
840-
// Hence `ptr::addr_of!`.
841-
let ptr: *const mem::ManuallyDrop<UnsafeCell<T>> =
842-
core::ptr::addr_of!(this.data.value);
843-
// There is no raw accessor on `ManuallyDrop`, but it's a `transparent` wrapper so we can
844-
// just `.cast()` that layer away.
845-
let ptr: *const UnsafeCell<T> = ptr.cast();
846-
// To handle the `UnsafeCell` layer, no need for casts, there is a dedicated API.
847-
let ptr: *mut T = UnsafeCell::raw_get(ptr);
848-
// Once we've gotten the pointer, the rest is easy: set the value and discriminants accordingly.
849-
ptr.write(value);
850-
this.state.set(State::Value);
851-
&*ptr
852-
}
853-
}
854-
State::Poisoned => panic!("Lazy instance has previously been poisoned"),
855-
}
778+
this.cell.get_or_init(|| match this.init.take() {
779+
Some(f) => f(),
780+
None => panic!("Lazy instance has previously been poisoned"),
781+
})
856782
}
857783

858784
/// Forces the evaluation of this lazy value and returns a mutable reference to
@@ -870,25 +796,14 @@ pub mod unsync {
870796
/// assert_eq!(*lazy, 92);
871797
/// ```
872798
pub fn force_mut(this: &mut Lazy<T, F>) -> &mut T {
873-
let state = this.state.get_mut();
874-
match state {
875-
State::Value => unsafe { (*this.data.value).get_mut() },
876-
State::Uninit => {
877-
// Safety: same reasoning as with `force`, except simpler since we can use `&mut` accesses.
878-
// (so we do not need to worry about any `UnsafeCell` shenanigans)
879-
let init = unsafe {
880-
*state = State::Poisoned;
881-
mem::ManuallyDrop::take(&mut this.data.init)
882-
};
883-
let value = mem::ManuallyDrop::new(init().into());
884-
unsafe {
885-
core::ptr::addr_of_mut!(this.data.value).write(value);
886-
*state = State::Value;
887-
(*this.data.value).get_mut()
888-
}
889-
}
890-
State::Poisoned => panic!("Lazy instance has previously been poisoned"),
799+
if this.cell.get_mut().is_none() {
800+
let value = match this.init.get_mut().take() {
801+
Some(f) => f(),
802+
None => panic!("Lazy instance has previously been poisoned"),
803+
};
804+
this.cell = OnceCell::with_value(value);
891805
}
806+
this.cell.get_mut().unwrap_or_else(|| unreachable!())
892807
}
893808

894809
/// Gets the reference to the result of this lazy value if
@@ -905,7 +820,7 @@ pub mod unsync {
905820
/// assert_eq!(Lazy::get(&lazy), Some(&92));
906821
/// ```
907822
pub fn get(this: &Lazy<T, F>) -> Option<&T> {
908-
matches!(this.state.get(), State::Value).then(|| unsafe { &*this.data.value.get() })
823+
this.cell.get()
909824
}
910825

911826
/// Gets the mutable reference to the result of this lazy value if
@@ -922,8 +837,7 @@ pub mod unsync {
922837
/// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92));
923838
/// ```
924839
pub fn get_mut(this: &mut Lazy<T, F>) -> Option<&mut T> {
925-
matches!(this.state.get_mut(), State::Value)
926-
.then(|| unsafe { (*this.data.value).get_mut() })
840+
this.cell.get_mut()
927841
}
928842
}
929843

@@ -1376,8 +1290,7 @@ pub mod sync {
13761290
let cell = this.cell;
13771291
let init = this.init;
13781292
cell.into_inner().ok_or_else(|| {
1379-
init.into_inner()
1380-
.unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
1293+
init.take().unwrap_or_else(|| panic!("Lazy instance has previously been poisoned"))
13811294
})
13821295
}
13831296
}

tests/it.rs

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,3 @@
1-
/// Put here any code relying on duck-typed `Lazy` and `OnceCell`, oblivious to
2-
/// their exact `sync` or `unsync` nature.
3-
macro_rules! tests_for_both {
4-
() => {
5-
#[test]
6-
fn lazy_does_drop() {
7-
type Counter = std::rc::Rc<()>;
8-
9-
let (counter, [c1, c2, c3]) = {
10-
let c = Counter::new(());
11-
(Counter::downgrade(&c), [(); 3].map(|()| c.clone()))
12-
};
13-
assert_eq!(counter.strong_count(), 3);
14-
15-
let lazy_1 = Lazy::<Counter, _>::new(|| c1);
16-
assert_eq!(counter.strong_count(), 3);
17-
drop(lazy_1);
18-
assert_eq!(
19-
counter.strong_count(),
20-
2,
21-
"dropping a `Lazy::Uninit` drops the `init` closure"
22-
);
23-
24-
let lazy_2 = Lazy::<Counter, _>::new(|| c2);
25-
Lazy::force(&lazy_2);
26-
assert_eq!(
27-
counter.strong_count(),
28-
2,
29-
"from `Lazy::Uninit` to `Lazy::Value` drops `init` but owns `value`"
30-
);
31-
drop(lazy_2);
32-
assert_eq!(counter.strong_count(), 1, "dropping a `Lazy::Value` drops its `value`");
33-
34-
let lazy_3 = Lazy::<Counter, _>::new(|| {
35-
None::<()>.unwrap();
36-
c3
37-
});
38-
assert_eq!(counter.strong_count(), 1);
39-
let _ = std::panic::catch_unwind(|| Lazy::force(&lazy_3)).expect_err("it panicked");
40-
assert_eq!(
41-
counter.strong_count(),
42-
0,
43-
"`init` closure is properly dropped despite panicking"
44-
);
45-
drop(lazy_3);
46-
assert_eq!(counter.strong_count(), 0, "what is dead may never die 🧟");
47-
}
48-
};
49-
}
50-
511
mod unsync {
522
use core::{
533
cell::Cell,
@@ -56,8 +6,6 @@ mod unsync {
566

577
use once_cell::unsync::{Lazy, OnceCell};
588

59-
tests_for_both!();
60-
619
#[test]
6210
fn once_cell() {
6311
let c = OnceCell::new();
@@ -299,16 +247,6 @@ mod unsync {
299247
cell.set(&s).unwrap();
300248
}
301249
}
302-
303-
#[test]
304-
fn assert_lazy_is_covariant_in_the_ctor() {
305-
#[allow(dead_code)]
306-
type AnyLazy<'f, T> = Lazy<T, Box<dyn 'f + FnOnce() -> T>>;
307-
308-
fn _for<'short, T>(it: *const (AnyLazy<'static, T>,)) -> *const (AnyLazy<'short, T>,) {
309-
it
310-
}
311-
}
312250
}
313251

314252
#[cfg(any(feature = "std", feature = "critical-section"))]
@@ -325,8 +263,6 @@ mod sync {
325263

326264
use once_cell::sync::{Lazy, OnceCell};
327265

328-
tests_for_both!();
329-
330266
#[test]
331267
fn once_cell() {
332268
let c = OnceCell::new();

0 commit comments

Comments
 (0)