1
/*
2
Copyright (C) 2021 Kunal Mehta <legoktm@debian.org>
3
Copyright (C) 2021 Erutuon
4

            
5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9

            
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14

            
15
You should have received a copy of the GNU General Public License
16
along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
use std::collections::{BTreeMap, HashMap};
19
use std::fmt::Display;
20

            
21
/// How to specify API parameters
22
///
23
/// API parameters can be specified in a number of different ways.
24
/// All the functions are typed to accept `Into<Params>`, so as long
25
/// as it can be converted into `Params`.
26
///
27
/// ```
28
/// # use std::collections::{BTreeMap, HashMap};
29
/// # use mwapi::Params;
30
///
31
/// let _: Params = HashMap::from([("action", "query"), ("titles", "Main Page")]).into();
32
/// let _: Params = (&HashMap::from([("action", "query"), ("titles", "Main Page")])).into();
33
/// let _: Params = BTreeMap::from([("action", "query"), ("titles", "Main Page")]).into();
34
/// let _: Params = [("action", "query"), ("titles", "Main Page")].into();
35
/// let _: Params = vec![("action", "query"), ("titles", "Main Page")].into();
36
/// ```
37
///
38
/// See the various `From` implementations below for a complete list.
39
#[derive(Debug, Clone, Default)]
40
pub struct Params {
41
    pub(crate) map: HashMap<String, String>,
42
}
43

            
44
impl Params {
45
886
    pub(crate) fn insert<K: Display, V: Display>(&mut self, key: K, value: V) {
46
886
        self.map.insert(key.to_string(), value.to_string());
47
886
    }
48

            
49
456
    pub(crate) fn get(&self, name: &str) -> Option<&String> {
50
456
        self.map.get(name)
51
456
    }
52

            
53
    /// Get the parameters as a HashMap
54
330
    pub fn as_map(&self) -> &HashMap<String, String> {
55
330
        &self.map
56
330
    }
57
}
58

            
59
pub(crate) enum RequestParams {
60
    Get(Params),
61
    Post(Params),
62
    #[cfg(feature = "upload")]
63
    Multipart(crate::upload::params::MultipartParams),
64
}
65

            
66
impl<P: Display, Q: Display> FromIterator<(P, Q)> for Params {
67
120
    fn from_iter<T: IntoIterator<Item = (P, Q)>>(iter: T) -> Self {
68
120
        Self {
69
120
            map: iter
70
120
                .into_iter()
71
304
                .map(|(k, v)| (k.to_string(), v.to_string()))
72
120
                .collect(),
73
120
        }
74
120
    }
75
}
76

            
77
impl<'a, P: Display, Q: Display> FromIterator<&'a (P, Q)> for Params {
78
236
    fn from_iter<T: IntoIterator<Item = &'a (P, Q)>>(iter: T) -> Self {
79
236
        Self {
80
236
            map: iter
81
236
                .into_iter()
82
1168
                .map(|(k, v)| (k.to_string(), v.to_string()))
83
236
                .collect(),
84
236
        }
85
236
    }
86
}
87

            
88
impl<P: Display, Q: Display> From<Vec<(P, Q)>> for Params {
89
2
    fn from(params: Vec<(P, Q)>) -> Self {
90
2
        Self::from_iter(params)
91
2
    }
92
}
93

            
94
impl<P: Display, Q: Display> From<&Vec<(P, Q)>> for Params {
95
110
    fn from(params: &Vec<(P, Q)>) -> Self {
96
110
        Self::from_iter(params)
97
110
    }
98
}
99

            
100
impl<P: Display, Q: Display> From<&[(P, Q)]> for Params {
101
2
    fn from(params: &[(P, Q)]) -> Self {
102
2
        Self::from_iter(params)
103
2
    }
104
}
105

            
106
impl<P: Display, Q: Display, const LENGTH: usize> From<[(P, Q); LENGTH]>
107
    for Params
108
{
109
22
    fn from(params: [(P, Q); LENGTH]) -> Self {
110
22
        Self::from_iter(params)
111
22
    }
112
}
113

            
114
impl<P: Display, Q: Display, const LENGTH: usize> From<&[(P, Q); LENGTH]>
115
    for Params
116
{
117
118
    fn from(params: &[(P, Q); LENGTH]) -> Self {
118
118
        Self::from_iter(params)
119
118
    }
120
}
121

            
122
impl<P: Display, Q: Display> From<HashMap<P, Q>> for Params {
123
86
    fn from(params: HashMap<P, Q>) -> Self {
124
86
        Self::from_iter(params)
125
86
    }
126
}
127

            
128
impl<P: Display, Q: Display> From<&HashMap<P, Q>> for Params {
129
2
    fn from(params: &HashMap<P, Q>) -> Self {
130
2
        Self::from_iter(params)
131
2
    }
132
}
133

            
134
impl<P: Display, Q: Display> From<BTreeMap<P, Q>> for Params {
135
    fn from(params: BTreeMap<P, Q>) -> Self {
136
        Self::from_iter(params)
137
    }
138
}
139

            
140
impl<P: Display, Q: Display> From<&BTreeMap<P, Q>> for Params {
141
    fn from(params: &BTreeMap<P, Q>) -> Self {
142
        Self::from_iter(params)
143
    }
144
}
145

            
146
#[test]
147
2
fn can_be_created_from_common_types() {
148
    type HashMap<K, V> = std::collections::HashMap<
149
        K,
150
        V,
151
        std::collections::hash_map::RandomState,
152
    >;
153
    macro_rules! convert_to_params {
154
        (
155
            $($source: expr,)*
156
        ) => {
157
            $(
158
                let _ = Params::from($source);
159
                let _ = Params::from_iter($source);
160
            )*
161
        };
162
    }
163
2
    convert_to_params!(
164
2
        [("a", "b")],
165
2
        &[("a", "b")],
166
2
        &[("a", "b")][..],
167
2
        vec![("a", "b")],
168
2
        &vec![("a", "b")],
169
2
        HashMap::from_iter([("a", "b")]),
170
2
        &HashMap::from_iter([("a", "b")]),
171
2
    );
172
2
}