pinboard_rs/api/
params.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7use std::borrow::Cow;
8
9use chrono::{DateTime, NaiveDate, Utc};
10use url::Url;
11
12/// A trait representing a parameter value
13pub trait ParamValue<'a> {
14    #[allow(clippy::wrong_self_convention)]
15    /// The parameter value as a string
16    fn as_value(&self) -> Cow<'a, str>;
17}
18
19impl ParamValue<'static> for bool {
20    fn as_value(&self) -> Cow<'static, str> {
21        if *self {
22            "true".into()
23        } else {
24            "false".into()
25        }
26    }
27}
28
29impl<'a> ParamValue<'a> for &'a str {
30    fn as_value(&self) -> Cow<'a, str> {
31        (*self).into()
32    }
33}
34
35impl ParamValue<'static> for String {
36    fn as_value(&self) -> Cow<'static, str> {
37        self.clone().into()
38    }
39}
40
41impl<'a> ParamValue<'a> for &'a String {
42    fn as_value(&self) -> Cow<'a, str> {
43        (*self).into()
44    }
45}
46
47impl<'a> ParamValue<'a> for Cow<'a, str> {
48    fn as_value(&self) -> Cow<'a, str> {
49        self.clone()
50    }
51}
52
53impl<'a, 'b: 'a> ParamValue<'a> for &'b Cow<'a, str> {
54    fn as_value(&self) -> Cow<'a, str> {
55        (*self).clone()
56    }
57}
58
59impl ParamValue<'static> for u8 {
60    fn as_value(&self) -> Cow<'static, str> {
61        format!("{}", self).into()
62    }
63}
64
65impl ParamValue<'static> for u64 {
66    fn as_value(&self) -> Cow<'static, str> {
67        format!("{}", self).into()
68    }
69}
70
71impl ParamValue<'static> for f64 {
72    fn as_value(&self) -> Cow<'static, str> {
73        format!("{}", self).into()
74    }
75}
76
77impl ParamValue<'static> for DateTime<Utc> {
78    fn as_value(&self) -> Cow<'static, str> {
79        self.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
80            .into()
81    }
82}
83
84impl ParamValue<'static> for NaiveDate {
85    fn as_value(&self) -> Cow<'static, str> {
86        format!("{}", self.format("%Y-%m-%d")).into()
87    }
88}
89
90impl ParamValue<'static> for &url::Url {
91    fn as_value(&self) -> Cow<'static, str> {
92        format!("{}", self).into()
93    }
94}
95
96/// A structure for query parameters.
97#[derive(Debug, Default, Clone)]
98pub struct QueryParams<'a> {
99    params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
100}
101
102impl<'a> QueryParams<'a> {
103    /// Push a single parameter.
104    pub fn push<'b, K, V>(&mut self, key: K, value: V) -> &mut Self
105    where
106        K: Into<Cow<'a, str>>,
107        V: ParamValue<'b>,
108        'b: 'a,
109    {
110        self.params.push((key.into(), value.as_value()));
111        self
112    }
113
114    /// Push a single parameter.
115    pub fn push_opt<'b, K, V>(&mut self, key: K, value: Option<V>) -> &mut Self
116    where
117        K: Into<Cow<'a, str>>,
118        V: ParamValue<'b>,
119        'b: 'a,
120    {
121        if let Some(value) = value {
122            self.params.push((key.into(), value.as_value()));
123        }
124        self
125    }
126
127    /// Push a set of parameters.
128    pub fn extend<'b, I, K, V>(&mut self, iter: I) -> &mut Self
129    where
130        I: Iterator<Item = (K, V)>,
131        K: Into<Cow<'a, str>>,
132        V: ParamValue<'b>,
133        'b: 'a,
134    {
135        self.params
136            .extend(iter.map(|(key, value)| (key.into(), value.as_value())));
137        self
138    }
139
140    /// Add the parameters to a URL.
141    pub fn add_to_url(&self, url: &mut Url) {
142        let mut pairs = url.query_pairs_mut();
143        pairs.extend_pairs(self.params.iter());
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use crate::api::ParamValue;
150
151    #[test]
152    fn bool_str() {
153        let items = &[(true, "true"), (false, "false")];
154
155        for (i, s) in items {
156            assert_eq!((*i).as_value(), *s);
157        }
158    }
159}