fennec_common/
sync_state.rs

1// Copyright 2023 Gregory Petrosyan <pgregory@pgregory.net>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use parking_lot::{Condvar, Mutex};
8use std::{
9    path::PathBuf,
10    sync::atomic::{AtomicBool, Ordering},
11    time::Duration,
12};
13
14use crate::workspace;
15
16#[derive(Default)]
17pub struct VfsChangeBuffer {
18    pub exit: bool,
19    // Scan roots usually correspond to directories with a manifest file, but they don't have to.
20    pub scan_roots: Vec<PathBuf>,
21    pub force_scan: bool,
22}
23
24#[derive(Default)]
25pub struct CoreChangeBuffer {
26    pub exit: bool,
27    pub module_updates: Vec<workspace::ModuleUpdate>,
28}
29
30pub struct SyncState {
31    vfs_changes: Mutex<VfsChangeBuffer>,
32    vfs_condvar: Condvar,
33    core_changes: Mutex<CoreChangeBuffer>,
34    core_changed: AtomicBool,
35    core_condvar: Condvar,
36}
37
38impl SyncState {
39    #[must_use]
40    pub fn new() -> SyncState {
41        SyncState {
42            vfs_changes: Mutex::new(VfsChangeBuffer::default()),
43            vfs_condvar: Condvar::new(),
44            core_changes: Mutex::new(CoreChangeBuffer::default()),
45            core_changed: AtomicBool::new(false),
46            core_condvar: Condvar::new(),
47        }
48    }
49
50    fn notify_vfs(&self) {
51        self.vfs_condvar.notify_one();
52    }
53
54    fn notify_core(&self) {
55        self.core_changed.store(true, Ordering::Release);
56        self.core_condvar.notify_one();
57    }
58
59    pub fn is_core_changed(&self) -> bool {
60        self.core_changed.load(Ordering::Acquire)
61    }
62
63    pub fn signal_exit(&self) {
64        {
65            let mut vfs = self.vfs_changes.lock();
66            vfs.exit = true;
67            self.notify_vfs();
68        }
69        {
70            let mut core = self.core_changes.lock();
71            core.exit = true;
72            self.notify_core();
73        }
74    }
75
76    pub fn signal_vfs_new_roots(&self, roots: Vec<PathBuf>) {
77        let mut vfs = self.vfs_changes.lock();
78        vfs.scan_roots.extend(roots);
79        self.notify_vfs();
80    }
81
82    pub fn signal_vfs_force_scan(&self) {
83        let mut vfs = self.vfs_changes.lock();
84        vfs.force_scan = true;
85        self.notify_vfs();
86    }
87
88    pub fn signal_core_module_updates(&self, updates: Vec<workspace::ModuleUpdate>) {
89        let mut core = self.core_changes.lock();
90        core.module_updates.extend(updates);
91        self.notify_core();
92    }
93
94    pub fn wait_vfs(&self, timeout: Duration) -> (VfsChangeBuffer, bool) {
95        let mut vfs = self.vfs_changes.lock();
96        let res = self.vfs_condvar.wait_for(&mut vfs, timeout);
97        (std::mem::take(&mut vfs), res.timed_out())
98    }
99
100    pub fn wait_core(&self) -> CoreChangeBuffer {
101        let mut core = self.core_changes.lock();
102        self.core_condvar.wait(&mut core);
103        std::mem::take(&mut core)
104    }
105}
106
107impl Default for SyncState {
108    fn default() -> Self {
109        Self::new()
110    }
111}