@@ -89,35 +89,45 @@ pub(crate) struct GdCellInner<T> {
8989impl < T > GdCellInner < T > {
9090 /// Creates a new cell storing `value`.
9191 pub fn new ( value : T ) -> Pin < Box < Self > > {
92- // Note – we are constructing it in two steps, because `CellState` uses non-null ptr to val inside our Cell.
9392 let mut uninitialized_cell: Box < MaybeUninit < Self > > = Box :: new_uninit ( ) ;
94- let ptr = uninitialized_cell. as_mut_ptr ( ) ;
93+ let uninitialized_cell_ptr = uninitialized_cell. as_mut_ptr ( ) ;
9594
96- unsafe {
97- ( & raw mut ( * ptr) . value ) . write ( UnsafeCell :: new ( value) ) ;
98- }
95+ // SAFETY: pointer to `value` is properly aligned.
96+ let value_ptr = unsafe {
97+ let value_ptr = & raw mut ( * uninitialized_cell_ptr) . value ;
98+ value_ptr. write ( UnsafeCell :: new ( value) ) ;
99+ value_ptr
100+ } ;
101+
102+ // SAFETY
103+ // `value_ptr` is properly aligned and points to initialized data.
104+ // Additionally, since Box::pin(...) is equivalent to Box::into_pin(Box::...) `value_ref`
105+ // will remain valid and refer to the same underlying value after pinning.
106+ let value_ref = unsafe { value_ptr. as_ref ( ) . unwrap ( ) } ;
99107
100- // SAFETY: Box::pin(...) is equivalent to Box::into_pin(Box::...) therefore our freshly initialized
101- // `val` is and will stay valid (i.e. will refer to the same place after pinning).
108+ // SAFETY: pointer to `state` is properly aligned.
109+ let state_ptr = unsafe { & raw mut ( * uninitialized_cell_ptr) . state } ;
110+
111+ // SAFETY: See above.
102112 unsafe {
103- let val = ( & raw const ( * ptr) . value ) . as_ref ( ) . unwrap ( ) ;
104- ( & raw mut ( * ptr) . state ) . write ( UnsafeCell :: new ( CellState :: new ( val) ) ) ;
113+ state_ptr. write ( UnsafeCell :: new ( CellState :: new ( value_ref) ) ) ;
105114 }
106115
107- Box :: into_pin ( unsafe { uninitialized_cell. assume_init ( ) } )
116+ Box :: into_pin (
117+ // SAFETY: All `GdCellInner` fields are valid.
118+ unsafe { uninitialized_cell. assume_init ( ) } ,
119+ )
108120 }
109121
110122 /// Returns a new shared reference to the contents of the cell.
111123 ///
112124 /// Fails if an accessible mutable reference exists.
113125 pub fn borrow ( self : Pin < & Self > ) -> Result < RefGuard < ' _ , T > , Box < dyn Error > > {
114- {
115- let state = unsafe { & mut * self . state . get ( ) } ;
116- state. borrow_state . increment_shared ( ) ?;
117- }
118-
119- let state = unsafe { & * self . state . get ( ) } ;
126+ // SAFETY: This is the only active reference to the state.
127+ let state = unsafe { self . cell_state_mut ( ) } ;
128+ state. borrow_state . increment_shared ( ) ?;
120129 let value = state. get_ptr ( ) ;
130+
121131 // SAFETY: `increment_shared` succeeded, therefore there cannot currently be any accessible mutable
122132 // references.
123133 unsafe { Ok ( RefGuard :: new ( & self . get_ref ( ) . state , value) ) }
@@ -127,7 +137,8 @@ impl<T> GdCellInner<T> {
127137 ///
128138 /// Fails if an accessible mutable reference exists, or a shared reference exists.
129139 pub fn borrow_mut ( self : Pin < & Self > ) -> Result < MutGuard < ' _ , T > , Box < dyn Error > > {
130- let state = unsafe { & mut * self . state . get ( ) } ;
140+ // SAFETY: This is the only active reference to the state.
141+ let state = unsafe { self . cell_state_mut ( ) } ;
131142 state. borrow_state . increment_mut ( ) ?;
132143 let count = state. borrow_state . mut_count ( ) ;
133144 let value = state. get_ptr ( ) ;
@@ -159,6 +170,25 @@ impl<T> GdCellInner<T> {
159170 InaccessibleGuard :: new ( & self . get_ref ( ) . state , current_ref)
160171 }
161172
173+ /// Returns a reference to the CellState.
174+ ///
175+ /// # Safety
176+ /// - The caller must ensure that there are no active exclusive references to the given state.
177+ unsafe fn cell_state ( & self ) -> & CellState < T > {
178+ // SAFETY: the underlying `CellState` will not be deallocated as long as Cell itself is alive.
179+ unsafe { & * self . state . get ( ) }
180+ }
181+
182+ /// Returns the exclusive reference to the CellState.
183+ ///
184+ /// # Safety
185+ /// - The caller must ensure that there are no active references to the given state.
186+ #[ allow( clippy:: mut_from_ref) ]
187+ unsafe fn cell_state_mut ( & self ) -> & mut CellState < T > {
188+ // SAFETY: the underlying `CellState` will not be deallocated as long as Cell itself is alive.
189+ unsafe { & mut * self . state . get ( ) }
190+ }
191+
162192 /// Returns `true` if there are any mutable or shared references, regardless of whether the mutable
163193 /// references are accessible or not.
164194 ///
@@ -169,16 +199,15 @@ impl<T> GdCellInner<T> {
169199 /// cell hands out a new borrow before it is destroyed. So we still need to ensure that this cannot
170200 /// happen at the same time.
171201 pub fn is_currently_bound ( self : Pin < & Self > ) -> bool {
172- let state = unsafe { & * self . state . get ( ) } ;
173-
202+ // SAFETY: this is the only reference to the `cell_state` in given context.
203+ let state = unsafe { self . cell_state ( ) } ;
174204 state. borrow_state . shared_count ( ) > 0 || state. borrow_state . mut_count ( ) > 0
175205 }
176206
177207 /// Similar to [`Self::is_currently_bound`] but only counts mutable references and ignores shared references.
178208 pub ( crate ) fn is_currently_mutably_bound ( self : Pin < & Self > ) -> bool {
179- let state = unsafe { & * self . state . get ( ) } ;
180-
181- state. borrow_state . mut_count ( ) > 0
209+ // SAFETY: this is the only reference to the `cell_state` in given context.
210+ unsafe { self . cell_state ( ) } . borrow_state . mut_count ( ) > 0
182211 }
183212}
184213
@@ -206,8 +235,6 @@ pub(crate) struct CellState<T> {
206235}
207236
208237impl < T > CellState < T > {
209- /// Create a new uninitialized state. Use [`initialize_ptr()`](CellState::initialize_ptr()) to initialize
210- /// it.
211238 fn new ( value : & UnsafeCell < T > ) -> Self {
212239 Self {
213240 borrow_state : BorrowState :: new ( ) ,
@@ -234,6 +261,17 @@ impl<T> CellState<T> {
234261 self . stack_depth -= 1 ;
235262 self . stack_depth
236263 }
264+
265+ /// Returns underlying [`BorrowState`].
266+ ///
267+ /// # Safety
268+ ///
269+ /// - `cell_state` must point to a valid reference.
270+ /// - There can't be any active reference to `CellState`.
271+ #[ allow( clippy:: mut_from_ref) ]
272+ pub ( crate ) unsafe fn borrow_state ( cell_state : & UnsafeCell < Self > ) -> & mut BorrowState {
273+ & mut cell_state. get ( ) . as_mut ( ) . unwrap ( ) . borrow_state
274+ }
237275}
238276
239277#[ cfg( test) ]
0 commit comments