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_path_and_query(
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.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}
61
62use http::uri::{Authority, Parts as UriParts, PathAndQuery, Scheme, Uri};
63
64pub fn construct_uri<T>(authority: &Authority, path_and_query: T) -> Result<Uri, http::Error>
65where
66 T: AsRef<[u8]> + 'static,
67{
68 let mut uri_parts = UriParts::default();
69 uri_parts.authority = Some(authority.clone());
70 uri_parts.scheme = Some(Scheme::HTTP);
71 uri_parts.path_and_query = Some(PathAndQuery::from_maybe_shared(path_and_query)?);
72 Ok(Uri::from_parts(uri_parts)?)
73}