1use std::borrow::Cow;
2use url::Url;
3
4pub trait ParamValue<'a> {
6 fn as_value(&self) -> Cow<'a, str>;
8}
9
10impl ParamValue<'static> for bool {
11 fn as_value(&self) -> Cow<'static, str> {
12 if *self {
13 "true".into()
14 } else {
15 "false".into()
16 }
17 }
18}
19
20impl<'a> ParamValue<'a> for &'a str {
21 fn as_value(&self) -> Cow<'a, str> {
22 (*self).into()
23 }
24}
25
26impl ParamValue<'static> for String {
27 fn as_value(&self) -> Cow<'static, str> {
28 self.clone().into()
29 }
30}
31
32impl<'a> ParamValue<'a> for &'a String {
33 fn as_value(&self) -> Cow<'a, str> {
34 (*self).into()
35 }
36}
37
38impl<'a> ParamValue<'a> for Cow<'a, str> {
39 fn as_value(&self) -> Cow<'a, str> {
40 self.clone()
41 }
42}
43
44impl<'a, 'b: 'a> ParamValue<'a> for &'b Cow<'a, str> {
45 fn as_value(&self) -> Cow<'a, str> {
46 (*self).clone()
47 }
48}
49
50impl ParamValue<'static> for u64 {
51 fn as_value(&self) -> Cow<'static, str> {
52 self.to_string().into()
53 }
54}
55
56impl ParamValue<'static> for f64 {
57 fn as_value(&self) -> Cow<'static, str> {
58 self.to_string().into()
59 }
60}
61
62#[derive(Debug, Default, Clone)]
64pub struct FormParams<'a> {
65 params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
66}
67
68impl<'a> FormParams<'a> {
69 pub fn push<'b, K, V>(&mut self, key: K, value: V) -> &mut Self
71 where
72 K: Into<Cow<'a, str>>,
73 V: ParamValue<'b>,
74 'b: 'a,
75 {
76 self.params.push((key.into(), value.as_value()));
77 self
78 }
79
80 pub fn push_opt<'b, K, V>(&mut self, key: K, value: Option<V>) -> &mut Self
82 where
83 K: Into<Cow<'a, str>>,
84 V: ParamValue<'b>,
85 'b: 'a,
86 {
87 if let Some(value) = value {
88 self.params.push((key.into(), value.as_value()));
89 }
90 self
91 }
92
93 pub fn extend<'b, I, K, V>(&mut self, iter: I) -> &mut Self
95 where
96 I: Iterator<Item = (K, V)>,
97 K: Into<Cow<'a, str>>,
98 V: ParamValue<'b>,
99 'b: 'a,
100 {
101 self.params
102 .extend(iter.map(|(key, value)| (key.into(), value.as_value())));
103 self
104 }
105
106 pub fn into_body(self) -> anyhow::Result<Option<(&'static str, Vec<u8>)>> {
108 let body = serde_urlencoded::to_string(self.params)?;
109 Ok(Some((
110 "application/x-www-form-urlencoded",
111 body.into_bytes(),
112 )))
113 }
114}
115
116#[derive(Debug, Default, Clone)]
118pub struct QueryParams<'a> {
119 params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
120}
121
122impl<'a> QueryParams<'a> {
123 pub fn push<'b, K, V>(&mut self, key: K, value: V) -> &mut Self
125 where
126 K: Into<Cow<'a, str>>,
127 V: ParamValue<'b>,
128 'b: 'a,
129 {
130 self.params.push((key.into(), value.as_value()));
131 self
132 }
133
134 pub fn push_opt<'b, K, V>(&mut self, key: K, value: Option<V>) -> &mut Self
136 where
137 K: Into<Cow<'a, str>>,
138 V: ParamValue<'b>,
139 'b: 'a,
140 {
141 if let Some(value) = value {
142 self.params.push((key.into(), value.as_value()));
143 }
144 self
145 }
146
147 pub fn extend<'b, I, K, V>(&mut self, iter: I) -> &mut Self
149 where
150 I: Iterator<Item = (K, V)>,
151 K: Into<Cow<'a, str>>,
152 V: ParamValue<'b>,
153 'b: 'a,
154 {
155 self.params
156 .extend(iter.map(|(key, value)| (key.into(), value.as_value())));
157 self
158 }
159
160 pub fn add_to_url(&self, url: &mut Url) {
162 let mut pairs = url.query_pairs_mut();
163 pairs.extend_pairs(self.params.iter());
164 }
165}