coven_database/
commit_scope.rs1use std::cell::Cell;
7use std::future::Future;
8use std::sync::atomic::{AtomicU64, Ordering};
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub struct CommitScope(u64);
15
16tokio::task_local! {
17 static TASK: CommitScope;
18}
19
20thread_local! {
21 #[cfg_attr(target_os = "android", allow(clippy::missing_const_for_thread_local))]
25 static THREAD: Cell<Option<CommitScope>> = const { Cell::new(None) };
26}
27
28impl CommitScope {
29 pub fn new() -> Self {
31 static NEXT: AtomicU64 = AtomicU64::new(1);
32 Self(NEXT.fetch_add(1, Ordering::Relaxed))
33 }
34
35 pub fn run<F: Future>(self, work: F) -> impl Future<Output = F::Output> {
39 TASK.scope(self, work)
40 }
41}
42
43impl Default for CommitScope {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49pub(crate) fn bind<R>(
52 run: impl FnOnce() -> R + Send + 'static,
53) -> impl FnOnce() -> R + Send + 'static {
54 let scope = TASK.try_with(|scope| *scope).ok();
55 #[cfg(any(test, feature = "test-utils"))]
56 let run = coven_foundation::test_work::bind(run);
57 move || enter(scope, run)
58}
59
60fn enter<R>(scope: Option<CommitScope>, run: impl FnOnce() -> R) -> R {
61 struct Restore(Option<CommitScope>);
62 impl Drop for Restore {
63 fn drop(&mut self) {
64 THREAD.with(|thread| thread.set(self.0));
65 }
66 }
67 let _restore = Restore(THREAD.with(|thread| thread.replace(scope)));
68 run()
69}
70
71pub(crate) fn committing() -> Option<CommitScope> {
73 THREAD.with(Cell::get)
74}