oauth1_request/request/
parameter_list.rs

1//! A [`Request`] with dynamic list of key-value parameter pairs.
2
3use core::borrow::Borrow;
4use core::cmp::Ordering;
5use core::fmt::Display;
6use core::iter::{Extend, FromIterator};
7use core::marker::PhantomData;
8
9use super::Request;
10use crate::serializer::Serializer;
11
12/// A [`Request`] with dynamic list of key-value parameter pairs.
13///
14/// This is like an array of `(K, V)` but the parameters are guaranteed to be sorted alphabetically.
15///
16/// ## Example
17///
18#[cfg_attr(feature = "alloc", doc = " ```")]
19#[cfg_attr(not(feature = "alloc"), doc = " ```ignore")]
20/// # extern crate oauth1_request as oauth;
21/// #
22/// let request = oauth::ParameterList::new([
23///     ("foo", 123),
24///     ("bar", 23),
25///     ("foo", 3),
26/// ]);
27///
28/// let form = oauth::to_form(&request);
29/// assert_eq!(form, "bar=23&foo=123&foo=3");
30/// ```
31pub struct ParameterList<
32    K,
33    V,
34    #[cfg(feature = "alloc")] A = alloc::vec::Vec<(K, V)>,
35    #[cfg(not(feature = "alloc"))] A,
36    P = (K, V),
37> {
38    list: A,
39    #[allow(clippy::type_complexity)]
40    marker: PhantomData<fn() -> (K, V, P)>,
41}
42
43/// An iterator over the elements of [`ParameterList`].
44///
45/// This struct is created by [`ParameterList::iter`] method.
46pub struct Iter<'a, K, V, P> {
47    inner: core::slice::Iter<'a, P>,
48    marker: PhantomData<fn() -> (K, V)>,
49}
50
51impl<K, V, A, P> ParameterList<K, V, A, P>
52where
53    K: AsRef<str>,
54    V: Display,
55    A: AsRef<[P]>,
56    P: Borrow<(K, V)>,
57{
58    /// Creates a new `ParameterList` from sorted `list`.
59    ///
60    /// Returns `None` if `list` is not sorted.
61    pub fn from_sorted(list: A) -> Option<Self> {
62        if is_sorted_by(list.as_ref(), cmp) {
63            Some(ParameterList {
64                list,
65                marker: PhantomData,
66            })
67        } else {
68            None
69        }
70    }
71}
72
73impl<K, V, A, P> ParameterList<K, V, A, P>
74where
75    K: AsRef<str>,
76    V: Display,
77    A: AsRef<[P]> + AsMut<[P]>,
78    P: Borrow<(K, V)>,
79{
80    /// Creates a new `ParameterList` from `list`.
81    ///
82    /// This function sorts `list`.
83    pub fn new(list: A) -> Self {
84        let mut ret = ParameterList {
85            list,
86            marker: PhantomData,
87        };
88        ret.sort();
89        ret
90    }
91}
92
93impl<K, V, A, P> ParameterList<K, V, A, P> {
94    /// Consumes the `ParameterList`, returning the wrapped value.
95    pub fn into_inner(self) -> A {
96        self.list
97    }
98}
99
100impl<K, V, A, P> ParameterList<K, V, A, P>
101where
102    K: AsRef<str>,
103    V: Display,
104    A: AsMut<[P]>,
105    P: Borrow<(K, V)>,
106{
107    fn sort(&mut self) {
108        self.list.as_mut().sort_unstable_by(cmp);
109    }
110}
111
112impl<K, V, A, P> ParameterList<K, V, A, P>
113where
114    A: AsRef<[P]>,
115    P: Borrow<(K, V)>,
116{
117    /// Returns an iterator over entries of the `ParameterList`.
118    pub fn iter(&self) -> Iter<'_, K, V, P> {
119        Iter {
120            inner: self.list.as_ref().iter(),
121            marker: PhantomData,
122        }
123    }
124}
125
126impl<K, V, A, P> AsRef<[P]> for ParameterList<K, V, A, P>
127where
128    A: AsRef<[P]>,
129{
130    fn as_ref(&self) -> &[P] {
131        self.list.as_ref()
132    }
133}
134
135impl<K, V, A, P> Default for ParameterList<K, V, A, P>
136where
137    K: AsRef<str>,
138    V: Display,
139    A: AsRef<[P]> + Default,
140    P: Borrow<(K, V)>,
141{
142    fn default() -> Self {
143        ParameterList {
144            list: A::default(),
145            marker: PhantomData,
146        }
147    }
148}
149
150impl<K, V, A, P> From<A> for ParameterList<K, V, A, P>
151where
152    K: AsRef<str>,
153    V: Display,
154    A: AsRef<[P]> + AsMut<[P]>,
155    P: Borrow<(K, V)>,
156{
157    fn from(list: A) -> Self {
158        ParameterList::new(list)
159    }
160}
161
162impl<K, V, A, P> FromIterator<P> for ParameterList<K, V, A, P>
163where
164    K: AsRef<str>,
165    V: Display,
166    A: AsRef<[P]> + AsMut<[P]> + FromIterator<P>,
167    P: Borrow<(K, V)>,
168{
169    fn from_iter<I>(iter: I) -> Self
170    where
171        I: IntoIterator<Item = P>,
172    {
173        ParameterList::new(iter.into_iter().collect())
174    }
175}
176
177impl<K, V, A, P> Extend<P> for ParameterList<K, V, A, P>
178where
179    K: AsRef<str>,
180    V: Display,
181    A: AsMut<[P]> + Extend<P>,
182    P: Borrow<(K, V)>,
183{
184    fn extend<I>(&mut self, iter: I)
185    where
186        I: IntoIterator<Item = P>,
187    {
188        self.list.extend(iter);
189        self.sort();
190    }
191}
192
193impl<K, V, A, P> Request for ParameterList<K, V, A, P>
194where
195    K: AsRef<str>,
196    V: Display,
197    A: AsRef<[P]>,
198    P: Borrow<(K, V)>,
199{
200    fn serialize<S>(&self, serializer: S) -> S::Output
201    where
202        S: Serializer,
203    {
204        return inner::<S, K, V, P>(self.list.as_ref(), serializer);
205
206        fn inner<S, K, V, P>(this: &[P], serializer: S) -> S::Output
207        where
208            S: Serializer,
209            K: AsRef<str>,
210            V: Display,
211            P: Borrow<(K, V)>,
212        {
213            super::AssertSorted::new(this.iter().map(|pair| {
214                let (ref k, ref v) = *pair.borrow();
215                (k, v)
216            }))
217            .serialize(serializer)
218        }
219    }
220}
221
222impl<'a, K: 'a, V: 'a, P> Iterator for Iter<'a, K, V, P>
223where
224    P: Borrow<(K, V)>,
225{
226    type Item = &'a (K, V);
227
228    fn next(&mut self) -> Option<Self::Item> {
229        self.inner.next().map(Borrow::borrow)
230    }
231}
232
233fn cmp<K, V, P>(lhs: &P, rhs: &P) -> Ordering
234where
235    K: AsRef<str>,
236    V: Display,
237    P: Borrow<(K, V)>,
238{
239    let (ref kl, ref vl) = *lhs.borrow();
240    let (ref kr, ref vr) = *rhs.borrow();
241    return inner(kl.as_ref(), vl, kr.as_ref(), vr);
242    fn inner<V: Display>(kl: &str, vl: &V, kr: &str, vr: &V) -> Ordering {
243        (kl, fmt_cmp::Cmp(vl)).cmp(&(kr, fmt_cmp::Cmp(vr)))
244    }
245}
246
247// TODO: Use `<[T]>::is_sorted_by` once it's stable.
248// <https://github.com/rust-lang/rust/pull/55045>
249fn is_sorted_by<T, F>(slice: &[T], mut cmp: F) -> bool
250where
251    F: FnMut(&T, &T) -> Ordering,
252{
253    slice
254        .windows(2)
255        .all(|slice| !matches!(cmp(&slice[1], &slice[0]), Ordering::Less))
256}