From ef472f1dc93ee4c953e296e7316ead7f3de4c09f Mon Sep 17 00:00:00 2001 From: bdbai Date: Mon, 13 Dec 2021 21:41:21 +0800 Subject: [PATCH 1/3] Stabilize arc_new_cyclic --- library/alloc/src/rc.rs | 39 +++++++++++++++++++++++----------- library/alloc/src/sync.rs | 44 +++++++++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 33bee4324fd38..b92fbac36d92e 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -374,32 +374,47 @@ impl Rc { } } - /// Constructs a new `Rc` using a weak reference to itself. Attempting - /// to upgrade the weak reference before this function returns will result - /// in a `None` value. However, the weak reference may be cloned freely and - /// stored for use at a later time. + /// Constructs a new `Rc` using a closure `data_fn` that has access to a + /// weak reference to the constructing `Rc`. + /// + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to prevent a memory leak. + /// In `data_fn`, initialization of `T` can make use of the weak reference + /// by cloning and storing it inside `T` for use at a later time. + /// + /// Since the new `Rc` is not fully-constructed until `Rc::new_cyclic` + /// returns, calling [`upgrade`] on the weak reference inside `data_fn` will + /// fail and result in a `None` value. + /// + /// # Panics + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak`] is dropped normally. /// /// # Examples /// /// ``` - /// #![feature(arc_new_cyclic)] /// #![allow(dead_code)] /// use std::rc::{Rc, Weak}; /// /// struct Gadget { - /// self_weak: Weak, - /// // ... more fields + /// me: Weak, /// } + /// /// impl Gadget { - /// pub fn new() -> Rc { - /// Rc::new_cyclic(|self_weak| { - /// Gadget { self_weak: self_weak.clone(), /* ... */ } - /// }) + /// /// Construct a reference counted Gadget. + /// fn new() -> Rc { + /// Rc::new_cyclic(|me| Gadget { me: me.clone() }) + /// } + /// + /// /// Return a reference counted pointer to Self. + /// fn me(&self) -> Rc { + /// self.me.upgrade().unwrap() /// } /// } /// ``` + /// [`upgrade`]: Weak::upgrade #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "arc_new_cyclic", issue = "75861")] + #[stable(feature = "arc_new_cyclic", since = "1.59.0")] pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Rc { // Construct the inner in the "uninitialized" state with a single // weak reference. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 7c065f37d1fa8..4deec0146e472 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -351,29 +351,47 @@ impl Arc { unsafe { Self::from_inner(Box::leak(x).into()) } } - /// Constructs a new `Arc` using a weak reference to itself. Attempting - /// to upgrade the weak reference before this function returns will result - /// in a `None` value. However, the weak reference may be cloned freely and - /// stored for use at a later time. + /// Constructs a new `Arc` using a closure `data_fn` that has access to + /// a weak reference to the constructing `Arc`. /// - /// # Examples + /// Generally, a structure circularly referencing itself, either directly or + /// indirectly, should not hold a strong reference to prevent a memory leak. + /// In `data_fn`, initialization of `T` can make use of the weak reference + /// by cloning and storing it inside `T` for use at a later time. + /// + /// Since the new `Arc` is not fully-constructed until + /// `Arc::new_cyclic` returns, calling [`upgrade`] on the weak + /// reference inside `data_fn` will fail and result in a `None` value. + /// + /// # Panics + /// If `data_fn` panics, the panic is propagated to the caller, and the + /// temporary [`Weak`] is dropped normally. + /// + /// # Example /// ``` - /// #![feature(arc_new_cyclic)] /// #![allow(dead_code)] - /// /// use std::sync::{Arc, Weak}; /// - /// struct Foo { - /// me: Weak, + /// struct Gadget { + /// me: Weak, /// } /// - /// let foo = Arc::new_cyclic(|me| Foo { - /// me: me.clone(), - /// }); + /// impl Gadget { + /// /// Construct a reference counted Gadget. + /// fn new() -> Arc { + /// Arc::new_cyclic(|me| Gadget { me: me.clone() }) + /// } + /// + /// /// Return a reference counted pointer to Self. + /// fn me(&self) -> Arc { + /// self.me.upgrade().unwrap() + /// } + /// } /// ``` + /// [`upgrade`]: Weak::upgrade #[cfg(not(no_global_oom_handling))] #[inline] - #[unstable(feature = "arc_new_cyclic", issue = "75861")] + #[stable(feature = "arc_new_cyclic", since = "1.59.0")] pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Arc { // Construct the inner in the "uninitialized" state with a single // weak reference. From ce31cbc7a35131d0386f03982d7cac8786f574f4 Mon Sep 17 00:00:00 2001 From: bdbai Date: Thu, 30 Dec 2021 21:55:18 +0800 Subject: [PATCH 2/3] use generic params for arc_new_cyclic --- library/alloc/src/rc.rs | 5 ++++- library/alloc/src/sync.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index b92fbac36d92e..e373be5bb6e2d 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -415,7 +415,10 @@ impl Rc { /// [`upgrade`]: Weak::upgrade #[cfg(not(no_global_oom_handling))] #[stable(feature = "arc_new_cyclic", since = "1.59.0")] - pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Rc { + pub fn new_cyclic(data_fn: F) -> Rc + where + F: FnOnce(&Weak) -> T, + { // Construct the inner in the "uninitialized" state with a single // weak reference. let uninit_ptr: NonNull<_> = Box::leak(box RcBox { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4deec0146e472..aba45f36c1532 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -392,7 +392,10 @@ impl Arc { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "arc_new_cyclic", since = "1.59.0")] - pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Arc { + pub fn new_cyclic(data_fn: F) -> Arc + where + F: FnOnce(&Weak) -> T, + { // Construct the inner in the "uninitialized" state with a single // weak reference. let uninit_ptr: NonNull<_> = Box::leak(box ArcInner { From 00e191c72d16135e74014bc621629524570bbf77 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 22 Jan 2022 15:48:42 +0000 Subject: [PATCH 3/3] Update stabilization version of arc_new_cyclic --- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index e373be5bb6e2d..85045f8d9864b 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -414,7 +414,7 @@ impl Rc { /// ``` /// [`upgrade`]: Weak::upgrade #[cfg(not(no_global_oom_handling))] - #[stable(feature = "arc_new_cyclic", since = "1.59.0")] + #[stable(feature = "arc_new_cyclic", since = "1.60.0")] pub fn new_cyclic(data_fn: F) -> Rc where F: FnOnce(&Weak) -> T, diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index aba45f36c1532..a20b84325aabd 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -391,7 +391,7 @@ impl Arc { /// [`upgrade`]: Weak::upgrade #[cfg(not(no_global_oom_handling))] #[inline] - #[stable(feature = "arc_new_cyclic", since = "1.59.0")] + #[stable(feature = "arc_new_cyclic", since = "1.60.0")] pub fn new_cyclic(data_fn: F) -> Arc where F: FnOnce(&Weak) -> T,