1
+ //! Public API facades for the implementation details of [`Zalsa`] and [`ZalsaLocal`].
1
2
use std:: { marker:: PhantomData , panic:: RefUnwindSafe , sync:: Arc } ;
2
3
3
4
use parking_lot:: { Condvar , Mutex } ;
@@ -9,6 +10,50 @@ use crate::{
9
10
Database , Event , EventKind ,
10
11
} ;
11
12
13
+ /// A handle to non-local database state.
14
+ pub struct StorageHandle < Db > {
15
+ // Note: Drop order is important, zalsa_impl needs to drop before coordinate
16
+ /// Reference to the database.
17
+ zalsa_impl : Arc < Zalsa > ,
18
+
19
+ // Note: Drop order is important, coordinate needs to drop after zalsa_impl
20
+ /// Coordination data for cancellation of other handles when `zalsa_mut` is called.
21
+ /// This could be stored in Zalsa but it makes things marginally cleaner to keep it separate.
22
+ coordinate : CoordinateDrop ,
23
+
24
+ /// We store references to `Db`
25
+ phantom : PhantomData < fn ( ) -> Db > ,
26
+ }
27
+
28
+ impl < Db : Database > Default for StorageHandle < Db > {
29
+ fn default ( ) -> Self {
30
+ Self {
31
+ zalsa_impl : Arc :: new ( Zalsa :: new :: < Db > ( ) ) ,
32
+ coordinate : CoordinateDrop ( Arc :: new ( Coordinate {
33
+ clones : Mutex :: new ( 1 ) ,
34
+ cvar : Default :: default ( ) ,
35
+ } ) ) ,
36
+ phantom : PhantomData ,
37
+ }
38
+ }
39
+ }
40
+
41
+ impl < Db > StorageHandle < Db > {
42
+ pub fn into_storage ( self ) -> Storage < Db > {
43
+ let StorageHandle {
44
+ zalsa_impl,
45
+ coordinate,
46
+ phantom,
47
+ } = self ;
48
+ Storage {
49
+ zalsa_impl,
50
+ coordinate,
51
+ phantom,
52
+ zalsa_local : ZalsaLocal :: new ( ) ,
53
+ }
54
+ }
55
+ }
56
+
12
57
/// Access the "storage" of a Salsa database: this is an internal plumbing trait
13
58
/// automatically implemented by `#[salsa::db]` applied to a struct.
14
59
///
@@ -21,9 +66,8 @@ pub unsafe trait HasStorage: Database + Clone + Sized {
21
66
fn storage_mut ( & mut self ) -> & mut Storage < Self > ;
22
67
}
23
68
24
- /// Concrete implementation of the [`Database`][] trait.
25
- /// Takes an optional type parameter `U` that allows you to thread your own data.
26
- pub struct Storage < Db : Database > {
69
+ /// Concrete implementation of the [`Database`] trait with local state that can be used to drive computations.
70
+ pub struct Storage < Db > {
27
71
// Note: Drop order is important, zalsa_impl needs to drop before coordinate
28
72
/// Reference to the database.
29
73
zalsa_impl : Arc < Zalsa > ,
@@ -39,13 +83,18 @@ pub struct Storage<Db: Database> {
39
83
/// We store references to `Db`
40
84
phantom : PhantomData < fn ( ) -> Db > ,
41
85
}
86
+
42
87
struct Coordinate {
43
88
/// Counter of the number of clones of actor. Begins at 1.
44
89
/// Incremented when cloned, decremented when dropped.
45
90
clones : Mutex < usize > ,
46
91
cvar : Condvar ,
47
92
}
48
93
94
+ // We cannot panic while holding a lock to `clones: Mutex<usize>` and therefore we cannot enter an
95
+ // inconsistent state.
96
+ impl RefUnwindSafe for Coordinate { }
97
+
49
98
impl < Db : Database > Default for Storage < Db > {
50
99
fn default ( ) -> Self {
51
100
Self {
@@ -61,6 +110,22 @@ impl<Db: Database> Default for Storage<Db> {
61
110
}
62
111
63
112
impl < Db : Database > Storage < Db > {
113
+ /// Discard the local state of this handle, turning it into a [`StorageHandle`] that is [`Sync`]
114
+ /// and [`std::panic::UnwindSafe`].
115
+ pub fn into_zalsa_handle ( self ) -> StorageHandle < Db > {
116
+ let Storage {
117
+ zalsa_impl,
118
+ coordinate,
119
+ phantom,
120
+ zalsa_local : _,
121
+ } = self ;
122
+ StorageHandle {
123
+ zalsa_impl,
124
+ coordinate,
125
+ phantom,
126
+ }
127
+ }
128
+
64
129
pub fn debug_input_entries < T > ( & self ) -> impl Iterator < Item = & input:: Value < T > >
65
130
where
66
131
T : input:: Configuration ,
@@ -99,7 +164,9 @@ impl<Db: Database> Storage<Db> {
99
164
. filter_map ( |page| page. cast_type :: < crate :: table:: Page < tracked_struct:: Value < T > > > ( ) )
100
165
. flat_map ( |pages| pages. slots ( ) )
101
166
}
167
+ }
102
168
169
+ impl < Db : Database > Storage < Db > {
103
170
/// Access the `Arc<Zalsa>`. This should always be
104
171
/// possible as `zalsa_impl` only becomes
105
172
/// `None` once we are in the `Drop` impl.
@@ -150,8 +217,6 @@ unsafe impl<T: HasStorage> ZalsaDatabase for T {
150
217
}
151
218
}
152
219
153
- impl < Db : Database > RefUnwindSafe for Storage < Db > { }
154
-
155
220
impl < Db : Database > Clone for Storage < Db > {
156
221
fn clone ( & self ) -> Self {
157
222
* self . coordinate . clones . lock ( ) += 1 ;
0 commit comments