Skip to content

Commit

Permalink
refactor(http): Use query string helper (#2348)
Browse files Browse the repository at this point in the history
  • Loading branch information
suneettipirneni committed May 31, 2024
1 parent 23414dc commit 438ace0
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 259 deletions.
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

0 comments on commit 438ace0

Please sign in to comment.