tauri_store/
event.rs

1use crate::error::Result;
2use crate::store::{Store, StoreId, StoreOptions, StoreState};
3use crate::CollectionMarker;
4use serde::Serialize;
5use tauri::{AppHandle, Emitter as _, EventTarget, Runtime, WebviewWindow, Window};
6
7pub const STORE_CONFIG_CHANGE_EVENT: &str = "tauri-store://config-change";
8pub const STORE_STATE_CHANGE_EVENT: &str = "tauri-store://state-change";
9pub const STORE_UNLOAD_EVENT: &str = "tauri-store://unload";
10
11#[derive(Clone, Debug, Serialize)]
12#[serde(rename_all = "camelCase")]
13pub(crate) struct StatePayload<'a> {
14  id: &'a StoreId,
15  state: &'a StoreState,
16}
17
18impl<'a, R, C> From<&'a Store<R, C>> for StatePayload<'a>
19where
20  R: Runtime,
21  C: CollectionMarker,
22{
23  fn from(store: &'a Store<R, C>) -> Self {
24    Self { id: &store.id, state: store.state() }
25  }
26}
27
28#[derive(Clone, Debug, Serialize)]
29#[serde(rename_all = "camelCase")]
30pub(crate) struct ConfigPayload<'a> {
31  id: &'a StoreId,
32  config: StoreOptions,
33}
34
35impl<'a, R, C> From<&'a Store<R, C>> for ConfigPayload<'a>
36where
37  R: Runtime,
38  C: CollectionMarker,
39{
40  fn from(store: &'a Store<R, C>) -> Self {
41    Self { id: &store.id, config: store.into() }
42  }
43}
44
45pub(crate) fn emit<R, T, S>(app: &AppHandle<R>, event: &str, payload: &T, source: S) -> Result<()>
46where
47  R: Runtime,
48  T: Serialize + ?Sized,
49  S: Into<EventSource>,
50{
51  let source: EventSource = source.into();
52  if let Some(source) = source.0 {
53    emit_filter(app, event, payload, |it| it != source)
54  } else {
55    emit_all(app, event, payload)
56  }
57}
58
59fn emit_all<R, T>(app: &AppHandle<R>, event: &str, payload: &T) -> Result<()>
60where
61  R: Runtime,
62  T: Serialize + ?Sized,
63{
64  app.emit_filter(event, payload, |target| {
65    matches!(target, EventTarget::WebviewWindow { .. })
66  })?;
67
68  Ok(())
69}
70
71fn emit_filter<R, T, F>(app: &AppHandle<R>, event: &str, payload: &T, f: F) -> Result<()>
72where
73  R: Runtime,
74  T: Serialize + ?Sized,
75  F: Fn(&str) -> bool,
76{
77  #[rustfmt::skip]
78  app.emit_filter(event, payload, |target| {
79    matches!(target, EventTarget::WebviewWindow { label } if f(label))
80  })?;
81
82  Ok(())
83}
84
85/// Source of a store event.
86pub struct EventSource(Option<String>);
87
88impl EventSource {
89  #[inline]
90  pub const fn is_backend(&self) -> bool {
91    self.0.is_none()
92  }
93}
94
95impl From<&str> for EventSource {
96  fn from(source: &str) -> Self {
97    Self(Some(String::from(source)))
98  }
99}
100
101impl From<Option<&str>> for EventSource {
102  fn from(source: Option<&str>) -> Self {
103    Self(source.map(String::from))
104  }
105}
106
107impl From<String> for EventSource {
108  fn from(source: String) -> Self {
109    Self(Some(source))
110  }
111}
112
113impl From<&String> for EventSource {
114  fn from(source: &String) -> Self {
115    Self(Some(source.to_owned()))
116  }
117}
118
119impl From<Option<String>> for EventSource {
120  fn from(source: Option<String>) -> Self {
121    Self(source)
122  }
123}
124
125impl From<&WebviewWindow> for EventSource {
126  fn from(window: &WebviewWindow) -> Self {
127    Self(Some(window.label().to_owned()))
128  }
129}
130
131impl From<&Window> for EventSource {
132  fn from(window: &Window) -> Self {
133    Self(Some(window.label().to_owned()))
134  }
135}