speedrun-api 1.3.0

A wrapper for the speedrun.com REST API
Documentation
use std::borrow::Borrow;

use serde::Serialize;
use url::Url;

use super::error::BodyError;

pub struct QueryParams<'a>(form_urlencoded::Serializer<'a, String>);

impl QueryParams<'_> {
    pub(crate) fn new() -> Self {
        Self(form_urlencoded::Serializer::new(String::new()))
    }

    #[allow(dead_code)]
    pub(crate) fn clear(&mut self) -> &mut Self {
        self.0.clear();
        self
    }

    #[allow(dead_code)]
    pub(crate) fn append_pair(
        &mut self,
        key: impl AsRef<str>,
        value: impl AsRef<str>,
    ) -> &mut Self {
        self.0.append_pair(key.as_ref(), value.as_ref());
        self
    }

    #[allow(dead_code)]
    pub(crate) fn extend_pairs<I, K, V>(&mut self, iter: I) -> &mut Self
    where
        I: IntoIterator,
        I::Item: Borrow<(K, V)>,
        K: AsRef<str>,
        V: AsRef<str>,
    {
        self.0.extend_pairs(iter);
        self
    }

    pub(crate) fn extend_from(&mut self, value: &impl Serialize) -> Result<&mut Self, BodyError> {
        value.serialize(self.serializer())?;
        Ok(self)
    }

    pub(crate) fn with(value: &impl Serialize) -> Result<Self, BodyError> {
        let mut out = Self::new();
        out.extend_from(value)?;
        Ok(out)
    }

    pub(crate) fn apply_to(self, url: &mut Url) {
        let query = &self.finish();
        if !query.is_empty() {
            url.set_query(Some(query))
        }
    }

    pub(crate) fn finish(mut self) -> String {
        self.0.finish()
    }
}

impl<'a> QueryParams<'a> {
    pub(crate) fn serializer<'b>(&'b mut self) -> serde_urlencoded::Serializer<'a, 'b, String> {
        serde_urlencoded::Serializer::new(&mut self.0)
    }
}

impl<'a> Default for QueryParams<'a> {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn empty_query_params() {
        let mut url = Url::parse("https://example.com/").unwrap();
        let params = QueryParams::new();
        params.apply_to(&mut url);

        assert_eq!(url.as_str(), "https://example.com/");

        let mut url = Url::parse("https://example.com/?foo=bar").unwrap();
        let params = QueryParams::new();
        params.apply_to(&mut url);

        assert_eq!(url.as_str(), "https://example.com/?foo=bar");
    }

    #[test]
    fn extend_from_empty() {
        #[derive(Debug, Serialize)]
        struct A {
            foo: String,
            bar: usize,
        }

        let mut params = QueryParams::new();

        let a = A {
            foo: "abcdef".into(),
            bar: 7,
        };

        params.extend_from(&a).unwrap();

        assert_eq!(params.finish(), String::from("foo=abcdef&bar=7"))
    }

    #[test]
    fn extend_from() {
        #[derive(Debug, Serialize)]
        struct A {
            foo: String,
            bar: usize,
        }

        let mut params = QueryParams::new();
        params.append_pair("some", "value");

        let a = A {
            foo: "abcdef".into(),
            bar: 7,
        };

        params.extend_from(&a).unwrap();

        assert_eq!(params.finish(), String::from("some=value&foo=abcdef&bar=7"))
    }
}