Skip to main content

tauri_plugin_sync_state/
mutator.rs

1use crate::{
2    commands::event_name,
3    error::Error,
4    slice::{StateRegistry, SyncState},
5};
6use std::ops::Deref;
7use tauri::{
8    ipc::{CommandArg, CommandItem, InvokeError},
9    AppHandle, Emitter, Manager, Runtime, Wry,
10};
11
12pub struct Mutator<S: SyncState, R: Runtime = Wry> {
13    app: AppHandle<R>,
14    snapshot: S,
15}
16
17impl<S: SyncState, R: Runtime> Deref for Mutator<S, R> {
18    type Target = S;
19    fn deref(&self) -> &S {
20        &self.snapshot
21    }
22}
23
24impl<S: SyncState, R: Runtime> Mutator<S, R> {
25    pub fn current(&self) -> &S {
26        &self.snapshot
27    }
28
29    pub fn reload(&mut self) -> Result<&S, Error> {
30        let registry = self.app.state::<StateRegistry>();
31        self.snapshot = registry.read::<S>()?;
32        Ok(&self.snapshot)
33    }
34
35    pub fn mutate(&mut self, f: impl FnOnce(&mut S)) {
36        if let Err(e) = self.try_mutate(f) {
37            log::error!("[sync-state] mutate<{}> failed: {e}", S::NAME);
38        }
39    }
40
41    pub fn try_mutate(&mut self, f: impl FnOnce(&mut S)) -> Result<(), Error> {
42        let registry = self.app.state::<StateRegistry>();
43        let next = registry.mutate::<S>(f)?;
44        self.snapshot = next.clone();
45        self.app
46            .emit(&event_name(S::NAME), next)
47            .map_err(|e| Error::Emit(e.to_string()))
48    }
49
50    pub async fn mutate_async<F, Fut>(&mut self, f: F)
51    where
52        F: FnOnce(S) -> Fut,
53        Fut: std::future::Future<Output = S>,
54    {
55        if let Err(e) = self.try_mutate_async(f).await {
56            log::error!("[sync-state] mutate_async<{}> failed: {e}", S::NAME);
57        }
58    }
59
60    pub async fn try_mutate_async<F, Fut>(&mut self, f: F) -> Result<(), Error>
61    where
62        F: FnOnce(S) -> Fut,
63        Fut: std::future::Future<Output = S>,
64    {
65        let current = {
66            let registry = self.app.state::<StateRegistry>();
67            registry.read::<S>()?
68        };
69        let updated = f(current).await;
70        let registry = self.app.state::<StateRegistry>();
71        registry.mutate::<S>(|s| *s = updated.clone())?;
72        self.snapshot = updated.clone();
73        self.app
74            .emit(&event_name(S::NAME), updated)
75            .map_err(|e| Error::Emit(e.to_string()))
76    }
77}
78
79impl<'de, S: SyncState, R: Runtime> CommandArg<'de, R> for Mutator<S, R> {
80    fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
81        let app: AppHandle<R> = command.message.webview().app_handle().clone();
82
83        let registry = app
84            .try_state::<StateRegistry>()
85            .ok_or_else(|| InvokeError::from(Error::PluginNotInitialized.to_string()))?;
86
87        let snapshot = registry
88            .read::<S>()
89            .map_err(|e| InvokeError::from(e.to_string()))?;
90
91        Ok(Mutator { app, snapshot })
92    }
93}