1 use salsa
::{Database, ParallelDatabase, Snapshot}
;
2 use std
::panic
::{self, AssertUnwindSafe}
;
3 use std
::sync
::atomic
::{AtomicU32, Ordering::SeqCst}
;
5 #[salsa::query_group(PanicSafelyStruct)]
6 trait PanicSafelyDatabase
: salsa
::Database
{
8 fn one(&self) -> usize;
10 fn panic_safely(&self) -> ();
12 fn outer(&self) -> ();
15 fn panic_safely(db
: &dyn PanicSafelyDatabase
) -> () {
16 assert_eq
!(db
.one(), 1);
19 static OUTER_CALLS
: AtomicU32
= AtomicU32
::new(0);
21 fn outer(db
: &dyn PanicSafelyDatabase
) -> () {
22 OUTER_CALLS
.fetch_add(1, SeqCst
);
26 #[salsa::database(PanicSafelyStruct)]
28 struct DatabaseStruct
{
29 storage
: salsa
::Storage
<Self>,
32 impl salsa
::Database
for DatabaseStruct {}
34 impl salsa
::ParallelDatabase
for DatabaseStruct
{
35 fn snapshot(&self) -> Snapshot
<Self> {
36 Snapshot
::new(DatabaseStruct
{
37 storage
: self.storage
.snapshot(),
43 fn should_panic_safely() {
44 let mut db
= DatabaseStruct
::default();
47 // Invoke `db.panic_safely() without having set `db.one`. `db.one` will
48 // return 0 and we should catch the panic.
49 let result
= panic
::catch_unwind(AssertUnwindSafe({
50 let db
= db
.snapshot();
51 move || db
.panic_safely()
53 assert
!(result
.is_err());
55 // Set `db.one` to 1 and assert ok
57 let result
= panic
::catch_unwind(AssertUnwindSafe(|| db
.panic_safely()));
58 assert
!(result
.is_ok());
60 // Check, that memoized outer is not invalidated by a panic
62 assert_eq
!(OUTER_CALLS
.load(SeqCst
), 0);
64 assert_eq
!(OUTER_CALLS
.load(SeqCst
), 1);
67 let result
= panic
::catch_unwind(AssertUnwindSafe(|| db
.outer()));
68 assert
!(result
.is_err());
69 assert_eq
!(OUTER_CALLS
.load(SeqCst
), 1);
73 assert_eq
!(OUTER_CALLS
.load(SeqCst
), 1);
78 fn storages_are_unwind_safe() {
79 fn check_unwind_safe
<T
: std
::panic
::UnwindSafe
>() {}
80 check_unwind_safe
::<&DatabaseStruct
>();
84 fn panics_clear_query_stack() {
85 let db
= DatabaseStruct
::default();
87 // Invoke `db.panic_if_not_one() without having set `db.input`. `db.input`
88 // will default to 0 and we should catch the panic.
89 let result
= panic
::catch_unwind(AssertUnwindSafe(|| db
.panic_safely()));
90 assert
!(result
.is_err());
92 // The database has been poisoned and any attempt to increment the
93 // revision should panic.
94 assert_eq
!(db
.salsa_runtime().active_query(), None
);