Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(http): Use query string helper #2348

Merged
merged 11 commits into from
May 31, 2024
2 changes: 1 addition & 1 deletion CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
identity and expression, level of experience, education, socioeconomic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.

Expand Down
1 change: 1 addition & 0 deletions twilight-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod response;
pub mod routing;

mod json;
mod query_formatter;

/// Discord API version used by this crate.
pub const API_VERSION: u8 = 10;
Expand Down
126 changes: 126 additions & 0 deletions twilight-http/src/query_formatter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use std::fmt::{Display, Formatter, Write};

/// A helper struct to write query paramseters to a formatter.
pub struct QueryStringFormatter<'w1, 'w2> {
formatter: &'w1 mut Formatter<'w2>,
is_first: bool,
}

impl<'w1, 'w2> QueryStringFormatter<'w1, 'w2> {
pub fn new(formatter: &'w1 mut Formatter<'w2>) -> Self {
Self {
formatter,
is_first: true,
}
}

/// Writes a query parameter to the formatter.
///
/// # Errors
///
/// This returns a [`std::fmt::Error`] if the formatter returns an error.
pub fn write_param(&mut self, key: &str, value: &impl Display) -> std::fmt::Result {
if self.is_first {
self.formatter.write_char('?')?;
self.is_first = false;
} else {
self.formatter.write_char('&')?;
}

self.formatter.write_str(key)?;
self.formatter.write_char('=')?;
Display::fmt(value, self.formatter)
}

/// Writes a query parameter to the formatter.
///
/// # Errors
///
/// This returns a [`std::fmt::Error`] if the formatter returns an error.
pub fn write_opt_param(&mut self, key: &str, value: Option<&impl Display>) -> std::fmt::Result {
if let Some(value) = value {
self.write_param(key, value)
} else {
Ok(())
}
}
}

/// Provides a display implementation for serializing iterable objects into
/// query params.
#[derive(Debug)]
pub struct QueryArray<T>(pub T);

impl<T, U> Display for QueryArray<T>
where
T: IntoIterator<Item = U> + Clone,
U: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut iter = self.0.clone().into_iter().peekable();

while let Some(item) = iter.next() {
Display::fmt(&item, f)?;
if iter.peek().is_some() {
f.write_str(",")?;
}
}

Ok(())
}
}

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

struct Test {
a: Option<u32>,
b: Option<String>,
}

impl Display for Test {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut writer = QueryStringFormatter::new(f);
writer.write_opt_param("a", self.a.as_ref())?;
writer.write_opt_param("b", self.b.as_ref())
}
}

#[test]
fn test_query_string_formatter_filled() {
let test = Test {
a: Some(1),
b: Some("hello".to_string()),
};

assert_eq!(test.to_string(), "?a=1&b=hello");
}

#[test]
fn test_query_string_formatter_empty() {
let test = Test { a: None, b: None };

assert_eq!(test.to_string(), "");
}

#[test]
fn test_query_string_formatter_single() {
let test = Test {
a: Some(1),
b: None,
};

assert_eq!(test.to_string(), "?a=1");
}

#[test]
fn test_query_array() {
let query_array = QueryArray([1, 2, 3]);
assert_eq!(query_array.to_string(), "1,2,3");

let params = vec!["a", "b", "c"];
let query_array = QueryArray(&params);
assert_eq!(query_array.to_string(), "a,b,c");
}
}
Loading