syncthing_types/
utils.rs

1pub struct QueryChars(bool);
2
3impl Default for QueryChars {
4    fn default() -> Self {
5        Self(false)
6    }
7}
8
9impl QueryChars {
10    pub fn next_char(&mut self) -> char {
11        if self.0 {
12            '&'
13        } else {
14            self.0 = true;
15            '?'
16        }
17    }
18}
19
20use serde::{Deserialize, Deserializer};
21
22pub fn default_on_null<'de, D, T: Default + Deserialize<'de>>(
23    deserializer: D,
24) -> Result<T, D::Error>
25where
26    D: Deserializer<'de>,
27{
28    let opt = Option::deserialize(deserializer)?;
29    Ok(opt.unwrap_or_default())
30}
31
32pub fn construct_event_url(
33    since: Option<u64>,
34    limit: Option<u64>,
35    events: impl AsRef<[crate::events::EventType]>,
36) -> serde_json::Result<String> {
37    let mut path_and_query = crate::routes::EVENTS_PATH.to_owned();
38    let events = events.as_ref();
39    let mut query_chars = QueryChars::default();
40    if !events.is_empty() {
41        let events = serde_json::to_string(&events)?
42            .chars()
43            .filter(|e| !matches!(e, '\"' | '[' | ']'))
44            .collect::<String>();
45        path_and_query.push(query_chars.next_char());
46        path_and_query.push_str("events=");
47        path_and_query.push_str(events.as_ref());
48    }
49    if let Some(since) = since {
50        path_and_query.push(query_chars.next_char());
51        path_and_query.push_str("since=");
52        path_and_query.push_str(since.to_string().as_ref());
53    }
54    if let Some(limit) = limit {
55        path_and_query.push(query_chars.next_char());
56        path_and_query.push_str("limit=");
57        path_and_query.push_str(limit.to_string().as_ref());
58    }
59    Ok(path_and_query)
60}