gen_api_wrapper/
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//
7// Originally from https://gitlab.kitware.com/utils/rust-gitlab
8//
9// Modified in an attempt to make it general beyond just gitlab
10//
11
12//! Endpoint prelude
13
14use std::borrow::Cow;
15
16use url::Url;
17
18use crate::error::BodyError;
19
20/// A trait representing a parameter value.
21pub trait ParamValue<'a> {
22    #[allow(clippy::wrong_self_convention)]
23    /// The parameter value as a string.
24    fn as_value(&self) -> Cow<'a, str>;
25}
26
27impl ParamValue<'static> for bool {
28    fn as_value(&self) -> Cow<'static, str> {
29        if *self {
30            "true".into()
31        } else {
32            "false".into()
33        }
34    }
35}
36
37impl<'a> ParamValue<'a> for &'a str {
38    fn as_value(&self) -> Cow<'a, str> {
39        (*self).into()
40    }
41}
42
43impl ParamValue<'static> for String {
44    fn as_value(&self) -> Cow<'static, str> {
45        self.clone().into()
46    }
47}
48
49impl<'a> ParamValue<'a> for &'a String {
50    fn as_value(&self) -> Cow<'a, str> {
51        (*self).into()
52    }
53}
54
55impl<'a> ParamValue<'a> for Cow<'a, str> {
56    fn as_value(&self) -> Cow<'a, str> {
57        self.clone()
58    }
59}
60
61impl<'a, 'b: 'a> ParamValue<'a> for &'b Cow<'a, str> {
62    fn as_value(&self) -> Cow<'a, str> {
63        (*self).clone()
64    }
65}
66
67impl ParamValue<'static> for u64 {
68    fn as_value(&self) -> Cow<'static, str> {
69        format!("{}", self).into()
70    }
71}
72
73impl ParamValue<'static> for f64 {
74    fn as_value(&self) -> Cow<'static, str> {
75        format!("{}", self).into()
76    }
77}
78
79/// A structure for form parameters.
80#[derive(Debug, Default, Clone)]
81pub struct FormParams<'a> {
82    params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
83}
84
85impl<'a> FormParams<'a> {
86    /// Push a single parameter.
87    pub fn push<'b, K, V>(&mut self, key: K, value: V) -> &mut Self
88    where
89        K: Into<Cow<'a, str>>,
90        V: ParamValue<'b>,
91        'b: 'a,
92    {
93        self.params.push((key.into(), value.as_value()));
94        self
95    }
96
97    /// Push a single parameter.
98    pub fn push_opt<'b, K, V>(&mut self, key: K, value: Option<V>) -> &mut Self
99    where
100        K: Into<Cow<'a, str>>,
101        V: ParamValue<'b>,
102        'b: 'a,
103    {
104        if let Some(value) = value {
105            self.params.push((key.into(), value.as_value()));
106        }
107        self
108    }
109
110    /// Push a set of parameters.
111    pub fn extend<'b, I, K, V>(&mut self, iter: I) -> &mut Self
112    where
113        I: Iterator<Item = (K, V)>,
114        K: Into<Cow<'a, str>>,
115        V: ParamValue<'b>,
116        'b: 'a,
117    {
118        self.params
119            .extend(iter.map(|(key, value)| (key.into(), value.as_value())));
120        self
121    }
122
123    /// Encode the parameters into a request body.
124    pub fn into_body(self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
125        let body = serde_urlencoded::to_string(self.params)?;
126        Ok(Some((
127            "application/x-www-form-urlencoded",
128            body.into_bytes(),
129        )))
130    }
131}
132
133/// A structure for query parameters.
134#[derive(Debug, Default, Clone)]
135pub struct QueryParams<'a> {
136    params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
137}
138
139impl<'a> QueryParams<'a> {
140    /// Push a single parameter.
141    pub fn push<'b, K, V>(&mut self, key: K, value: V) -> &mut Self
142    where
143        K: Into<Cow<'a, str>>,
144        V: ParamValue<'b>,
145        'b: 'a,
146    {
147        self.params.push((key.into(), value.as_value()));
148        self
149    }
150
151    /// Push a single parameter.
152    pub fn push_opt<'b, K, V>(&mut self, key: K, value: Option<V>) -> &mut Self
153    where
154        K: Into<Cow<'a, str>>,
155        V: ParamValue<'b>,
156        'b: 'a,
157    {
158        if let Some(value) = value {
159            self.params.push((key.into(), value.as_value()));
160        }
161        self
162    }
163
164    /// Push a set of parameters.
165    pub fn extend<'b, I, K, V>(&mut self, iter: I) -> &mut Self
166    where
167        I: Iterator<Item = (K, V)>,
168        K: Into<Cow<'a, str>>,
169        V: ParamValue<'b>,
170        'b: 'a,
171    {
172        self.params
173            .extend(iter.map(|(key, value)| (key.into(), value.as_value())));
174        self
175    }
176
177    /// Add the parameters to a URL.
178    pub fn add_to_url(&self, url: &mut Url) {
179        let mut pairs = url.query_pairs_mut();
180        pairs.extend_pairs(self.params.iter());
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use super::*;
187
188    #[test]
189    fn bool_str() {
190        let items = &[(true, "true"), (false, "false")];
191
192        for (i, s) in items {
193            assert_eq!((*i).as_value(), *s);
194        }
195    }
196}