1use std::borrow::Cow;
15
16use url::Url;
17
18pub trait ParamValue<'a> {
20 #[allow(clippy::wrong_self_convention)]
21 fn as_value(&self) -> Cow<'a, str>;
23}
24
25impl ParamValue<'static> for bool {
26 fn as_value(&self) -> Cow<'static, str> {
27 if *self {
28 "true".into()
29 } else {
30 "false".into()
31 }
32 }
33}
34
35impl<'a> ParamValue<'a> for &'a str {
36 fn as_value(&self) -> Cow<'a, str> {
37 (*self).into()
38 }
39}
40
41impl ParamValue<'static> for String {
42 fn as_value(&self) -> Cow<'static, str> {
43 self.clone().into()
44 }
45}
46
47impl<'a> ParamValue<'a> for &'a String {
48 fn as_value(&self) -> Cow<'a, str> {
49 (*self).into()
50 }
51}
52
53impl<'a> ParamValue<'a> for Cow<'a, str> {
54 fn as_value(&self) -> Cow<'a, str> {
55 self.clone()
56 }
57}
58
59impl<'a, 'b: 'a> ParamValue<'a> for &'b Cow<'a, str> {
60 fn as_value(&self) -> Cow<'a, str> {
61 (*self).clone()
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
77#[derive(Debug, Default, PartialEq, Eq, Clone)]
79pub struct FormParams<'a> {
80 params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
81}
82
83impl<'a> FormParams<'a> {
84 pub fn push<'b, K, V>(&mut self, key: K, value: V) -> &mut Self
86 where
87 K: Into<Cow<'a, str>>,
88 V: ParamValue<'b>,
89 'b: 'a,
90 {
91 self.params.push((key.into(), value.as_value()));
92 self
93 }
94
95 pub fn push_opt<'b, K, V>(&mut self, key: K, value: Option<V>) -> &mut Self
97 where
98 K: Into<Cow<'a, str>>,
99 V: ParamValue<'b>,
100 'b: 'a,
101 {
102 if let Some(value) = value {
103 self.params.push((key.into(), value.as_value()));
104 }
105 self
106 }
107
108 pub fn extend<'b, I, K, V>(&mut self, iter: I) -> &mut Self
110 where
111 I: Iterator<Item = (K, V)>,
112 K: Into<Cow<'a, str>>,
113 V: ParamValue<'b>,
114 'b: 'a,
115 {
116 self.params
117 .extend(iter.map(|(key, value)| (key.into(), value.as_value())));
118 self
119 }
120}
121
122#[derive(Debug, Default, PartialEq, Eq, Clone)]
124pub struct QueryParams<'a> {
125 params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
126}
127
128impl<'a> QueryParams<'a> {
129 pub fn push<'b, K, V>(&mut self, key: K, value: V) -> &mut Self
131 where
132 K: Into<Cow<'a, str>>,
133 V: ParamValue<'b>,
134 'b: 'a,
135 {
136 self.params.push((key.into(), value.as_value()));
137 self
138 }
139
140 pub fn push_opt<'b, K, V>(&mut self, key: K, value: Option<V>) -> &mut Self
142 where
143 K: Into<Cow<'a, str>>,
144 V: ParamValue<'b>,
145 'b: 'a,
146 {
147 if let Some(value) = value {
148 self.params.push((key.into(), value.as_value()));
149 }
150 self
151 }
152
153 pub fn extend<'b, I, K, V>(&mut self, iter: I) -> &mut Self
155 where
156 I: Iterator<Item = (K, V)>,
157 K: Into<Cow<'a, str>>,
158 V: ParamValue<'b>,
159 'b: 'a,
160 {
161 self.params
162 .extend(iter.map(|(key, value)| (key.into(), value.as_value())));
163 self
164 }
165
166 pub fn add_to_url(&self, url: &mut Url) {
168 let mut pairs = url.query_pairs_mut();
169 pairs.extend_pairs(self.params.iter());
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn bool_str() {
179 let items = &[(true, "true"), (false, "false")];
180
181 for (i, s) in items {
182 assert_eq!((*i).as_value(), *s);
183 }
184 }
185}