Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
18ad5a5
Add a regression test for issue-72793
JohnTitor Aug 19, 2020
aa40c02
Unstable Book: add links to tracking issues for FFI features
ArekPiekarz Aug 26, 2020
f03d0b3
`impl Rc::new_cyclic`
mental32 Aug 27, 2020
42fb270
typo
mental32 Aug 29, 2020
bb5e79c
Link vec doc to & reference
pickfire Aug 29, 2020
20a6866
Try removing [prim@reference]
pickfire Aug 30, 2020
81e85ce
Move to Arc::clone(&x) over x.clone() in library/std
poliorcetics Aug 30, 2020
6b75e3d
Move to Arc::clone(&x) over x.clone() in library/core
poliorcetics Aug 30, 2020
0f301e8
Removed [inline] and copied over comments from Arc::new_cyclic
mental32 Sep 1, 2020
dddc5ff
rename MaybeUninit slice methods
RalfJung Sep 1, 2020
0e0a47d
document remaining unsafety in maybe_uninit.rs
RalfJung Sep 2, 2020
acac5c6
Add regression test
JulianKnodt Sep 2, 2020
8783c62
Add missing link in README
camelid Sep 2, 2020
3e29fdb
Remove a number of vec UI tests, make them unit tests in the alloc li…
CraftSpider Sep 3, 2020
791f93c
Allow try blocks as the argument to return expressions
scottmcm Sep 3, 2020
4231fbc
Condense StringReader's API to a single function
matklad Sep 3, 2020
4df6490
Link & primitive using relative link
pickfire Sep 3, 2020
ccf41dd
Rename IsJoint -> Spacing
matklad Sep 3, 2020
c6ab3ff
Add test for checking if-let or-patterns
JulianKnodt Aug 16, 2020
2278c72
Remove vec-to_str.rs, merge the remaining test in with vec
CraftSpider Sep 3, 2020
a2e077e
Make `Ipv4Addr` and `Ipv6Addr` const tests unit tests under `library`
CDirkx Sep 3, 2020
8c93125
Address review comments on `Peekable::next_if`
jyn514 Sep 3, 2020
7b823df
Link to `#capacity-and-reallocation` when using with_capacity
jyn514 Sep 3, 2020
538e198
Move various ui const tests to `library`
CDirkx Sep 4, 2020
85146b9
Add slice primitive link to vec
pickfire Sep 4, 2020
1893161
Rollup merge of #75580 - JulianKnodt:or_pattern, r=wesleywiser
matklad Sep 4, 2020
23c6435
Rollup merge of #75695 - JohnTitor:regression-test, r=Dylan-DPC
matklad Sep 4, 2020
ab1e517
Rollup merge of #75954 - ArekPiekarz:unstable_book_ffi_tracking_issue…
matklad Sep 4, 2020
621605f
Rollup merge of #75994 - mental32:impl-rc-new-cyclic, r=KodrAus
matklad Sep 4, 2020
f199602
Rollup merge of #76060 - pickfire:patch-12, r=jyn514
matklad Sep 4, 2020
5734041
Rollup merge of #76128 - poliorcetics:doc-use-arc-clone, r=KodrAus
matklad Sep 4, 2020
c191b36
Rollup merge of #76217 - RalfJung:maybe-uninit-slice, r=KodrAus
matklad Sep 4, 2020
149d339
Rollup merge of #76229 - camelid:patch-3, r=jonas-schievink
matklad Sep 4, 2020
0f9bbea
Rollup merge of #76257 - JulianKnodt:i75777, r=Dylan-DPC
matklad Sep 4, 2020
602babc
Rollup merge of #76273 - CraftSpider:master, r=matklad
matklad Sep 4, 2020
8155dd4
Rollup merge of #76274 - scottmcm:fix-76271, r=petrochenkov
matklad Sep 4, 2020
3ea07a3
Rollup merge of #76291 - matklad:spacing, r=petrochenkov
matklad Sep 4, 2020
405de83
Rollup merge of #76299 - CDirkx:ip-tests, r=matklad
matklad Sep 4, 2020
c40f193
Rollup merge of #76302 - jyn514:peekable-2, r=Dylan-DPC
matklad Sep 4, 2020
3b0e366
Rollup merge of #76303 - jyn514:vec-assert-doc, r=Dylan-DPC
matklad Sep 4, 2020
7758c4d
Rollup merge of #76305 - CDirkx:const-tests, r=matklad
matklad Sep 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,50 @@ impl<T> Rc<T> {
)
}

/// Constructs a new `Rc<T>` 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.
#[unstable(feature = "arc_new_cyclic", issue = "75861")]
pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> {
// Construct the inner in the "uninitialized" state with a single
// weak reference.
let uninit_ptr: NonNull<_> = Box::leak(box RcBox {
strong: Cell::new(0),
weak: Cell::new(1),
value: mem::MaybeUninit::<T>::uninit(),
})
.into();

let init_ptr: NonNull<RcBox<T>> = uninit_ptr.cast();

let weak = Weak { ptr: init_ptr };

// It's important we don't give up ownership of the weak pointer, or
// else the memory might be freed by the time `data_fn` returns. If
// we really wanted to pass ownership, we could create an additional
// weak pointer for ourselves, but this would result in additional
// updates to the weak reference count which might not be necessary
// otherwise.
let data = data_fn(&weak);

unsafe {
let inner = init_ptr.as_ptr();
ptr::write(&raw mut (*inner).value, data);

let prev_value = (*inner).strong.get();
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
(*inner).strong.set(1);
}

let strong = Rc::from_inner(init_ptr);

// Strong references should collectively own a shared weak reference,
// so don't run the destructor for our old weak reference.
mem::forget(weak);
strong
}

/// Constructs a new `Rc` with uninitialized contents.
///
/// # Examples
Expand Down
66 changes: 66 additions & 0 deletions library/alloc/src/rc/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,69 @@ fn test_array_from_slice() {
let a: Result<Rc<[u32; 2]>, _> = r.clone().try_into();
assert!(a.is_err());
}

#[test]
fn test_rc_cyclic_with_zero_refs() {
struct ZeroRefs {
inner: Weak<ZeroRefs>,
}

let zero_refs = Rc::new_cyclic(|inner| {
assert_eq!(inner.strong_count(), 0);
assert!(inner.upgrade().is_none());
ZeroRefs { inner: Weak::new() }
});

assert_eq!(Rc::strong_count(&zero_refs), 1);
assert_eq!(Rc::weak_count(&zero_refs), 0);
assert_eq!(zero_refs.inner.strong_count(), 0);
assert_eq!(zero_refs.inner.weak_count(), 0);
}

#[test]
fn test_rc_cyclic_with_one_ref() {
struct OneRef {
inner: Weak<OneRef>,
}

let one_ref = Rc::new_cyclic(|inner| {
assert_eq!(inner.strong_count(), 0);
assert!(inner.upgrade().is_none());
OneRef { inner: inner.clone() }
});

assert_eq!(Rc::strong_count(&one_ref), 1);
assert_eq!(Rc::weak_count(&one_ref), 1);

let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap();
assert!(Rc::ptr_eq(&one_ref, &one_ref2));

assert_eq!(one_ref.inner.strong_count(), 2);
assert_eq!(one_ref.inner.weak_count(), 1);
}

#[test]
fn test_rc_cyclic_with_two_ref() {
struct TwoRefs {
inner: Weak<TwoRefs>,
inner1: Weak<TwoRefs>,
}

let two_refs = Rc::new_cyclic(|inner| {
assert_eq!(inner.strong_count(), 0);
assert!(inner.upgrade().is_none());
TwoRefs { inner: inner.clone(), inner1: inner.clone() }
});

assert_eq!(Rc::strong_count(&two_refs), 1);
assert_eq!(Rc::weak_count(&two_refs), 2);

let two_ref3 = Weak::upgrade(&two_refs.inner).unwrap();
assert!(Rc::ptr_eq(&two_refs, &two_ref3));

let two_ref2 = Weak::upgrade(&two_refs.inner1).unwrap();
assert!(Rc::ptr_eq(&two_refs, &two_ref2));

assert_eq!(Rc::strong_count(&two_refs), 3);
assert_eq!(Rc::weak_count(&two_refs), 2);
}