use axum::http::{
Uri,
uri::InvalidUriParts as RealInvalidUriParts,
};
use core::{
error::Error,
fmt::{Display, Formatter, self},
hash::BuildHasher,
};
use std::collections::HashMap;
use tracing::warn;
use url::form_urlencoded;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InvalidUriParts(String);
impl Display for InvalidUriParts {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Invalid URI parts: {}", self.0)
}
}
impl Error for InvalidUriParts {}
pub fn extract_uri_query_parts(uri: &Uri) -> HashMap<String, String> {
uri
.query()
.map(|v| form_urlencoded::parse(v.as_bytes()).into_owned().collect())
.unwrap_or_default()
}
pub fn build_uri<P, K, V, H>(path: P, params: &HashMap<K, V, H>) -> Result<Uri, InvalidUriParts>
where
P: AsRef<str>,
K: AsRef<str> + Display,
V: AsRef<str> + Display,
H: BuildHasher,
{
Uri::builder()
.path_and_query(format!(
"{}?{}",
path.as_ref(),
params
.iter()
.map(|(k, v)| format!("{k}={v}"))
.collect::<Vec<String>>()
.join("&")
,
))
.build()
.map_err(|err| {
if !err.is::<RealInvalidUriParts>() {
warn!("Expected InvalidUriParts, but got a different error type: {err}");
}
InvalidUriParts(err.to_string())
})
}