datastar/
patch_signals.rs

1//! [`PatchSignals`] patches signals into the signal store.
2
3use {
4    crate::{DatastarEvent, consts},
5    core::time::Duration,
6};
7
8/// [`PatchSignals`] patches signals into the signal store.
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct PatchSignals {
11    /// `id` can be used by the backend to replay events.
12    /// This is part of the SSE spec and is used to tell the browser how to handle the event.
13    /// For more details see <https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#id>
14    pub id: Option<String>,
15    /// `retry` is part of the SSE spec and is used to tell the browser how long to wait before reconnecting if the connection is lost.
16    /// For more details see <https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#retry>
17    pub retry: Duration,
18    /// `signals` is a JavaScript object or JSON string that will be sent to the browser to update signals in the signals.
19    /// The data ***must*** evaluate to a valid JavaScript. It will be converted to signals by the Datastar client side.
20    pub signals: String,
21    /// Whether to patch the signal only if it does not already exist.
22    /// If not provided, the Datastar client side will default to false, which will cause the data to be patched into the signals.
23    pub only_if_missing: bool,
24}
25
26impl PatchSignals {
27    /// Creates a new [`PatchSignals`] event with the given signals.
28    pub fn new(signals: impl Into<String>) -> Self {
29        Self {
30            id: None,
31            retry: Duration::from_millis(consts::DEFAULT_SSE_RETRY_DURATION),
32            signals: signals.into(),
33            only_if_missing: consts::DEFAULT_PATCH_SIGNALS_ONLY_IF_MISSING,
34        }
35    }
36
37    /// Sets the `id` of the [`PatchSignals`] event.
38    pub fn id(mut self, id: impl Into<String>) -> Self {
39        self.id = Some(id.into());
40        self
41    }
42
43    /// Sets the `retry` of the [`PatchSignals`] event.
44    pub fn retry(mut self, retry: Duration) -> Self {
45        self.retry = retry;
46        self
47    }
48
49    /// Sets the `only_if_missing` of the [`PatchSignals`] event.
50    pub fn only_if_missing(mut self, only_if_missing: bool) -> Self {
51        self.only_if_missing = only_if_missing;
52        self
53    }
54
55    /// Converts this [`PatchSignals`] into a [`DatastarEvent`].
56    #[inline]
57    pub fn into_datastar_event(mut self) -> DatastarEvent {
58        let id = self.id.take();
59        self.convert_to_datastar_event_inner(id)
60    }
61
62    /// Copy this [`PatchSignals`] as a [`DatastarEvent`].
63    #[inline]
64    pub fn as_datastar_event(&self) -> DatastarEvent {
65        self.convert_to_datastar_event_inner(self.id.clone())
66    }
67
68    fn convert_to_datastar_event_inner(&self, id: Option<String>) -> DatastarEvent {
69        let mut data: Vec<String> = Vec::new();
70
71        if self.only_if_missing != consts::DEFAULT_PATCH_SIGNALS_ONLY_IF_MISSING {
72            data.push(format!(
73                "{} {}",
74                consts::ONLY_IF_MISSING_DATALINE_LITERAL,
75                self.only_if_missing
76            ));
77        }
78
79        for line in self.signals.lines() {
80            data.push(format!("{} {line}", consts::SIGNALS_DATALINE_LITERAL));
81        }
82
83        DatastarEvent {
84            event: consts::EventType::PatchSignals,
85            id,
86            retry: self.retry,
87            data,
88        }
89    }
90}
91
92impl From<&PatchSignals> for DatastarEvent {
93    #[inline]
94    fn from(val: &PatchSignals) -> Self {
95        val.as_datastar_event()
96    }
97}
98
99impl From<PatchSignals> for DatastarEvent {
100    #[inline]
101    fn from(val: PatchSignals) -> Self {
102        val.into_datastar_event()
103    }
104}