@@ -2,7 +2,7 @@ use alloc::alloc::Layout;
22use alloc:: rc:: Rc ;
33use core:: cell:: UnsafeCell ;
44use core:: marker:: PhantomData ;
5- use core:: mem;
5+ use core:: mem:: ManuallyDrop ;
66use core:: ops:: Deref ;
77use core:: ptr:: { self , drop_in_place, NonNull } ;
88use core:: borrow:: Borrow ;
@@ -66,32 +66,52 @@ impl<T: Trace> Cc<T> {
6666 } )
6767 }
6868
69- /// Takes out the value inside a [`Cc`].
70- ///
71- /// # Panics
72- /// Panics if the [`Cc`] is not unique (see [`is_unique`]).
73- ///
74- /// [`is_unique`]: fn@Cc::is_unique
69+ /// Returns the inner value, if the [`Cc`] has exactly one strong reference and the collector is not collecting, finalizing or dropping.
70+ ///
71+ /// Otherwise, an [`Err`] is returned with the same [`Cc`] this method was called on.
72+ ///
73+ /// This will succeed even if there are outstanding weak references.
7574 #[ inline]
7675 #[ track_caller]
77- pub fn into_inner ( self ) -> T {
78- assert ! ( self . is_unique ( ) , "Cc<_> is not unique" ) ;
76+ pub fn try_unwrap ( self ) -> Result < T , Self > {
77+ let cc = ManuallyDrop :: new ( self ) ; // Never drop the Cc
7978
80- assert ! (
81- ! self . counter_marker ( ) . is_in_list_or_queue ( ) ,
82- "Cc<_> is being used by the collector and inner value cannot be taken out (this might have happen inside Trace, Finalize or Drop implementations)."
83- ) ;
79+ if cc . strong_count ( ) != 1 {
80+ // No need to access the state here
81+ return Err ( ManuallyDrop :: into_inner ( cc ) ) ;
82+ }
8483
85- // Make sure self is not into POSSIBLE_CYCLES before deallocating
86- remove_from_list ( self . inner . cast ( ) ) ;
84+ let res = try_state ( |state| {
85+ if state. is_collecting ( ) || state. is_dropping ( ) {
86+ return None ;
87+ }
8788
88- // SAFETY: self is unique and is not inside any list
89- unsafe {
90- let t = ptr:: read ( self . inner ( ) . get_elem ( ) ) ;
91- let layout = self . inner ( ) . layout ( ) ;
92- let _ = try_state ( |state| cc_dealloc ( self . inner , layout, state) ) ;
93- mem:: forget ( self ) ; // Don't call drop on this Cc
94- t
89+ #[ cfg( feature = "finalization" ) ]
90+ if state. is_finalizing ( ) {
91+ // To make this method behave the same outside of collections, unwrapping while finalizing is prohibited
92+ return None ;
93+ }
94+
95+ remove_from_list ( cc. inner . cast ( ) ) ;
96+
97+ // Disable upgrading weak ptrs
98+ #[ cfg( feature = "weak-ptrs" ) ]
99+ cc. inner ( ) . drop_metadata ( ) ;
100+ // There's no reason here to call CounterMarker::set_dropped, since the pointed value will not be dropped
101+
102+ // SAFETY: cc is unique and no weak pointer can be upgraded
103+ let t = unsafe { ptr:: read ( cc. inner ( ) . get_elem ( ) ) } ;
104+ let layout = cc. inner ( ) . layout ( ) ;
105+ // SAFETY: cc is unique, is not inside any list and no weak pointer can be upgraded
106+ unsafe {
107+ cc_dealloc ( cc. inner , layout, state) ;
108+ }
109+ Some ( t)
110+ } ) ;
111+
112+ match res {
113+ Ok ( Some ( t) ) => Ok ( t) ,
114+ _ => Err ( ManuallyDrop :: into_inner ( cc) ) ,
95115 }
96116 }
97117}
@@ -109,12 +129,6 @@ impl<T: ?Sized + Trace> Cc<T> {
109129 self . counter_marker ( ) . counter ( ) as u32
110130 }
111131
112- /// Returns `true` if the strong reference count is `1`, `false` otherwise.
113- #[ inline]
114- pub fn is_unique ( & self ) -> bool {
115- self . strong_count ( ) == 1
116- }
117-
118132 /// Makes the value in the managed allocation finalizable again.
119133 ///
120134 /// # Panics
0 commit comments