i3status_rs/
wrappers.rs

1use crate::errors::*;
2
3use serde::de::{self, Deserialize, Deserializer};
4use std::borrow::Cow;
5use std::fmt::{self, Display};
6use std::marker::PhantomData;
7use std::ops::RangeInclusive;
8use std::str::FromStr;
9use std::time::Duration;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct Seconds<const ALLOW_ONCE: bool = true>(pub Duration);
13
14impl<const ALLOW_ONCE: bool> From<u64> for Seconds<ALLOW_ONCE> {
15    fn from(v: u64) -> Self {
16        Self::new(v)
17    }
18}
19
20impl<const ALLOW_ONCE: bool> Seconds<ALLOW_ONCE> {
21    pub fn new(value: u64) -> Self {
22        Self(Duration::from_secs(value))
23    }
24
25    pub fn timer(self) -> tokio::time::Interval {
26        let mut timer = tokio::time::interval_at(tokio::time::Instant::now() + self.0, self.0);
27        timer.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
28        timer
29    }
30
31    pub fn seconds(self) -> u64 {
32        self.0.as_secs()
33    }
34}
35
36impl<'de, const ALLOW_ONCE: bool> Deserialize<'de> for Seconds<ALLOW_ONCE> {
37    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
38    where
39        D: Deserializer<'de>,
40    {
41        struct SecondsVisitor<const ALLOW_ONCE: bool>;
42
43        impl<const ALLOW_ONCE: bool> de::Visitor<'_> for SecondsVisitor<ALLOW_ONCE> {
44            type Value = Seconds<ALLOW_ONCE>;
45
46            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
47                formatter.write_str("\"once\", i64 or f64")
48            }
49
50            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
51            where
52                E: de::Error,
53            {
54                if ALLOW_ONCE && v == "once" {
55                    Ok(Seconds(Duration::from_secs(60 * 60 * 24 * 365)))
56                } else {
57                    Err(E::custom(format!("'{v}' is not a valid duration")))
58                }
59            }
60
61            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
62            where
63                E: de::Error,
64            {
65                Ok(Seconds(Duration::from_secs(v as u64)))
66            }
67
68            fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
69            where
70                E: de::Error,
71            {
72                Ok(Seconds(Duration::from_secs_f64(v)))
73            }
74        }
75
76        deserializer.deserialize_any(SecondsVisitor)
77    }
78}
79
80#[derive(Debug, Clone)]
81pub struct ShellString(pub Cow<'static, str>);
82
83impl<T> From<T> for ShellString
84where
85    T: Into<Cow<'static, str>>,
86{
87    fn from(v: T) -> Self {
88        Self(v.into())
89    }
90}
91
92impl<'de> Deserialize<'de> for ShellString {
93    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
94    where
95        D: Deserializer<'de>,
96    {
97        struct Visitor;
98
99        impl de::Visitor<'_> for Visitor {
100            type Value = ShellString;
101
102            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
103                formatter.write_str("text")
104            }
105
106            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
107            where
108                E: de::Error,
109            {
110                Ok(ShellString(v.to_string().into()))
111            }
112        }
113
114        deserializer.deserialize_any(Visitor)
115    }
116}
117
118impl ShellString {
119    pub fn new<T: Into<Cow<'static, str>>>(value: T) -> Self {
120        Self(value.into())
121    }
122
123    pub fn expand(&self) -> Result<Cow<str>> {
124        shellexpand::full(&self.0).error("Failed to expand string")
125    }
126}
127
128/// A map with keys being ranges.
129#[derive(Debug, Default, Clone)]
130pub struct RangeMap<K, V>(Vec<(RangeInclusive<K>, V)>);
131
132impl<K, V> RangeMap<K, V> {
133    pub fn get(&self, key: &K) -> Option<&V>
134    where
135        K: PartialOrd,
136    {
137        self.0
138            .iter()
139            .find_map(|(k, v)| k.contains(key).then_some(v))
140    }
141}
142
143impl<K, V> From<Vec<(RangeInclusive<K>, V)>> for RangeMap<K, V> {
144    fn from(vec: Vec<(RangeInclusive<K>, V)>) -> Self {
145        Self(vec)
146    }
147}
148
149impl<'de, K, V> Deserialize<'de> for RangeMap<K, V>
150where
151    K: FromStr,
152    K::Err: Display,
153    V: Deserialize<'de>,
154{
155    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
156    where
157        D: Deserializer<'de>,
158    {
159        struct Visitor<K, V>(PhantomData<(K, V)>);
160
161        impl<'de, K, V> de::Visitor<'de> for Visitor<K, V>
162        where
163            K: FromStr,
164            K::Err: Display,
165            V: Deserialize<'de>,
166        {
167            type Value = RangeMap<K, V>;
168
169            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
170                formatter.write_str("range map")
171            }
172
173            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
174            where
175                A: de::MapAccess<'de>,
176            {
177                let mut vec = Vec::with_capacity(map.size_hint().unwrap_or(2));
178                while let Some((range, val)) = map.next_entry::<String, V>()? {
179                    let (start, end) = range
180                        .split_once("..")
181                        .error("invalid range")
182                        .serde_error()?;
183                    let start: K = start.parse().serde_error()?;
184                    let end: K = end.parse().serde_error()?;
185                    vec.push((start..=end, val));
186                }
187                Ok(RangeMap(vec))
188            }
189        }
190
191        deserializer.deserialize_map(Visitor(PhantomData))
192    }
193}
194
195#[derive(Debug, Clone)]
196pub struct SerdeRegex(pub regex::Regex);
197
198impl PartialEq for SerdeRegex {
199    fn eq(&self, other: &Self) -> bool {
200        self.0.as_str() == other.0.as_str()
201    }
202}
203
204impl Eq for SerdeRegex {}
205
206impl std::hash::Hash for SerdeRegex {
207    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
208        self.0.as_str().hash(state);
209    }
210}
211
212impl<'de> Deserialize<'de> for SerdeRegex {
213    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
214    where
215        D: Deserializer<'de>,
216    {
217        struct Visitor;
218
219        impl de::Visitor<'_> for Visitor {
220            type Value = SerdeRegex;
221
222            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
223                formatter.write_str("a regex")
224            }
225
226            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
227            where
228                E: de::Error,
229            {
230                regex::Regex::new(v).map(SerdeRegex).map_err(E::custom)
231            }
232        }
233
234        deserializer.deserialize_any(Visitor)
235    }
236}
237
238/// Display a slice. Similar to Debug impl for slice, but uses Display impl for elements.
239pub struct DisplaySlice<'a, T>(pub &'a [T]);
240
241impl<T: Display> Display for DisplaySlice<'_, T> {
242    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243        struct DisplayAsDebug<'a, T>(&'a T);
244        impl<T: Display> fmt::Debug for DisplayAsDebug<'_, T> {
245            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246                fmt::Display::fmt(self.0, f)
247            }
248        }
249        f.debug_list()
250            .entries(self.0.iter().map(DisplayAsDebug))
251            .finish()
252    }
253}