44
55use std:: {
66 any:: { Any , TypeId } ,
7- cell:: UnsafeCell ,
87 collections:: HashMap ,
98 hash:: BuildHasherDefault ,
9+ pin:: Pin ,
1010 sync:: Mutex ,
1111} ;
1212
@@ -97,56 +97,56 @@ impl std::hash::Hasher for IdentHash {
9797 }
9898}
9999
100- type TypeIdMap = HashMap < TypeId , Box < dyn Any > , BuildHasherDefault < IdentHash > > ;
100+ /// Safety:
101+ /// - The `key` must equal to `(*value).type_id()`, see the safety doc in methods of [StateManager] for details.
102+ /// - Once you insert a value, you can't remove/mutated/move it anymore, see [StateManager::try_get] for details.
103+ type TypeIdMap = HashMap < TypeId , Pin < Box < dyn Any + Sync + Send > > , BuildHasherDefault < IdentHash > > ;
101104
102105/// The Tauri state manager.
103106#[ derive( Debug ) ]
104107pub struct StateManager {
105- map : Mutex < UnsafeCell < TypeIdMap > > ,
108+ map : Mutex < TypeIdMap > ,
106109}
107110
108- // SAFETY: data is accessed behind a lock
109- unsafe impl Sync for StateManager { }
110- unsafe impl Send for StateManager { }
111-
112111impl StateManager {
113112 pub ( crate ) fn new ( ) -> Self {
114113 Self {
115114 map : Default :: default ( ) ,
116115 }
117116 }
118117
119- fn with_map_ref < ' a , F : FnOnce ( & ' a TypeIdMap ) -> R , R > ( & ' a self , f : F ) -> R {
120- let map = self . map . lock ( ) . unwrap ( ) ;
121- let map = map. get ( ) ;
122- // SAFETY: safe to access since we are holding a lock
123- f ( unsafe { & * map } )
124- }
125-
126- fn with_map_mut < F : FnOnce ( & mut TypeIdMap ) -> R , R > ( & self , f : F ) -> R {
127- let mut map = self . map . lock ( ) . unwrap ( ) ;
128- let map = map. get_mut ( ) ;
129- f ( map)
130- }
131-
132118 pub ( crate ) fn set < T : Send + Sync + ' static > ( & self , state : T ) -> bool {
133- self . with_map_mut ( |map| {
134- let type_id = TypeId :: of :: < T > ( ) ;
135- let already_set = map. contains_key ( & type_id) ;
136- if !already_set {
137- map. insert ( type_id, Box :: new ( state) as Box < dyn Any > ) ;
138- }
139- !already_set
140- } )
119+ let mut map = self . map . lock ( ) . unwrap ( ) ;
120+ let type_id = TypeId :: of :: < T > ( ) ;
121+ let already_set = map. contains_key ( & type_id) ;
122+ if !already_set {
123+ let ptr = Box :: new ( state) as Box < dyn Any + Sync + Send > ;
124+ let pinned_ptr = Box :: into_pin ( ptr) ;
125+ map. insert (
126+ type_id,
127+ // SAFETY: keep the type of the key is the same as the type of the value,
128+ // see [try_get] methods for details.
129+ pinned_ptr,
130+ ) ;
131+ }
132+ !already_set
141133 }
142134
143- pub ( crate ) fn unmanage < T : Send + Sync + ' static > ( & self ) -> Option < T > {
144- self . with_map_mut ( |map| {
145- let type_id = TypeId :: of :: < T > ( ) ;
146- map
147- . remove ( & type_id)
148- . and_then ( |ptr| ptr. downcast ( ) . ok ( ) . map ( |b| * b) )
149- } )
135+ /// SAFETY: Calling this method will move the `value`,
136+ /// which will cause references obtained through [Self::try_get] to dangle.
137+ pub ( crate ) unsafe fn unmanage < T : Send + Sync + ' static > ( & self ) -> Option < T > {
138+ let mut map = self . map . lock ( ) . unwrap ( ) ;
139+ let type_id = TypeId :: of :: < T > ( ) ;
140+ let pinned_ptr = map. remove ( & type_id) ?;
141+ // SAFETY: The caller decides to break the immovability/safety here, then OK, just let it go.
142+ let ptr = unsafe { Pin :: into_inner_unchecked ( pinned_ptr) } ;
143+ let value = unsafe {
144+ ptr
145+ . downcast :: < T > ( )
146+ // SAFETY: the type of the key is the same as the type of the value
147+ . unwrap_unchecked ( )
148+ } ;
149+ Some ( * value)
150150 }
151151
152152 /// Gets the state associated with the specified type.
@@ -158,12 +158,18 @@ impl StateManager {
158158
159159 /// Gets the state associated with the specified type.
160160 pub fn try_get < T : Send + Sync + ' static > ( & self ) -> Option < State < ' _ , T > > {
161- self . with_map_ref ( |map| {
162- map
163- . get ( & TypeId :: of :: < T > ( ) )
164- . and_then ( |ptr| ptr. downcast_ref :: < T > ( ) )
165- . map ( State )
166- } )
161+ let map = self . map . lock ( ) . unwrap ( ) ;
162+ let type_id = TypeId :: of :: < T > ( ) ;
163+ let ptr = map. get ( & type_id) ?;
164+ let value = unsafe {
165+ ptr
166+ . downcast_ref :: < T > ( )
167+ // SAFETY: the type of the key is the same as the type of the value
168+ . unwrap_unchecked ( )
169+ } ;
170+ // SAFETY: We ensure the lifetime of `value` is the same as [StateManager] and `value` will not be mutated/moved.
171+ let v_ref = unsafe { & * ( value as * const T ) } ;
172+ Some ( State ( v_ref) )
167173 }
168174}
169175
@@ -197,8 +203,9 @@ mod tests {
197203 let state = StateManager :: new ( ) ;
198204 assert ! ( state. set( 1u32 ) ) ;
199205 assert_eq ! ( * state. get:: <u32 >( ) , 1 ) ;
200- assert ! ( state. unmanage:: <u32 >( ) . is_some( ) ) ;
201- assert ! ( state. unmanage:: <u32 >( ) . is_none( ) ) ;
206+ // safety: the reference returned by `try_get` is already dropped.
207+ assert ! ( unsafe { state. unmanage:: <u32 >( ) } . is_some( ) ) ;
208+ assert ! ( unsafe { state. unmanage:: <u32 >( ) } . is_none( ) ) ;
202209 assert_eq ! ( state. try_get:: <u32 >( ) , None ) ;
203210 assert ! ( state. set( 2u32 ) ) ;
204211 assert_eq ! ( * state. get:: <u32 >( ) , 2 ) ;
0 commit comments