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