tauri_plugin_sync_state/
mutator.rs1use 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}