tauri_plugin_widgets/
apply.rs1use serde::{Deserialize, Serialize};
4use std::collections::hash_map::DefaultHasher;
5use std::hash::{Hash, Hasher};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(tag = "reason", rename_all = "camelCase")]
10pub enum SkipReason {
11 Unchanged {
13 hash: u64,
15 },
16 NoInstances,
18 TransportUnavailable {
20 name: String,
22 },
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(tag = "outcome", rename_all = "camelCase")]
28pub enum ReloadOutcome {
29 Ok,
31 Throttled {
33 #[serde(rename = "remainingSecs")]
35 remaining_secs: u64,
36 },
37 Skipped {
39 why: String,
41 },
42 Failed {
44 error: String,
46 },
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52#[serde(rename_all = "camelCase")]
53pub struct ApplyOutcome {
54 pub written: bool,
56 pub reload: ReloadOutcome,
58 pub transports: Vec<String>,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
62 pub skip: Option<SkipReason>,
63}
64
65impl ApplyOutcome {
66 pub fn unchanged(hash: u64) -> Self {
68 Self {
69 written: false,
70 reload: ReloadOutcome::Skipped {
71 why: "unchanged".into(),
72 },
73 transports: Vec::new(),
74 skip: Some(SkipReason::Unchanged { hash }),
75 }
76 }
77}
78
79pub fn config_content_hash(json: &str) -> u64 {
81 let mut hasher = DefaultHasher::new();
82 json.hash(&mut hasher);
83 hasher.finish()
84}
85
86pub fn throttle_remaining_secs(elapsed_secs: u64, min_interval: u64) -> Option<u64> {
88 if min_interval == 0 || elapsed_secs >= min_interval {
89 None
90 } else {
91 Some(min_interval.saturating_sub(elapsed_secs))
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn unchanged_serializes_camel_case() {
101 let o = ApplyOutcome::unchanged(42);
102 let v = serde_json::to_value(&o).unwrap();
103 assert_eq!(v["written"], false);
104 assert_eq!(v["reload"]["outcome"], "skipped");
105 assert_eq!(v["skip"]["reason"], "unchanged");
106 assert_eq!(v["skip"]["hash"], 42);
107 }
108
109 #[test]
110 fn throttled_remaining_secs_camel() {
111 let r = ReloadOutcome::Throttled {
112 remaining_secs: 840,
113 };
114 let v = serde_json::to_value(&r).unwrap();
115 assert_eq!(v["outcome"], "throttled");
116 assert_eq!(v["remainingSecs"], 840);
117 }
118
119 #[test]
120 fn throttle_remaining_math() {
121 assert_eq!(throttle_remaining_secs(0, 0), None);
122 assert_eq!(throttle_remaining_secs(100, 0), None);
123 assert_eq!(throttle_remaining_secs(60, 900), Some(840));
124 assert_eq!(throttle_remaining_secs(900, 900), None);
125 assert_eq!(throttle_remaining_secs(901, 900), None);
126 }
127
128 #[test]
129 fn same_json_same_hash() {
130 assert_eq!(
131 config_content_hash(r#"{"version":1}"#),
132 config_content_hash(r#"{"version":1}"#)
133 );
134 assert_ne!(
135 config_content_hash(r#"{"version":1}"#),
136 config_content_hash(r#"{"version":2}"#)
137 );
138 }
139}