use std::collections::BTreeMap;
use anyhow::Result;
use serde::Deserialize;
#[derive(Deserialize)]
#[serde(untagged)]
pub enum OneOrMany<T> {
One(T),
Many(Vec<T>),
}
impl<T: std::fmt::Debug> std::fmt::Debug for OneOrMany<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::One(t) => t.fmt(f),
Self::Many(v) => v.fmt(f),
}
}
}
#[tracing::instrument(name = "urlquery.decode", err)]
pub fn decode(x: String) -> Result<String> {
Ok(urlencoding::decode(&x)?.into_owned())
}
#[tracing::instrument(name = "urlquery.decode_object")]
pub fn decode_object(x: String) -> BTreeMap<String, Vec<String>> {
let parsed = form_urlencoded::parse(x.as_bytes()).into_owned();
let mut decoded_object: BTreeMap<String, Vec<String>> = BTreeMap::new();
for (k, v) in parsed {
decoded_object.entry(k).or_default().push(v);
}
decoded_object
}
#[tracing::instrument(name = "urlquery.encode")]
pub fn encode(x: String) -> String {
form_urlencoded::byte_serialize(x.as_bytes()).collect()
}
#[tracing::instrument(name = "urlquery.encode_object")]
pub fn encode_object(x: BTreeMap<String, OneOrMany<String>>) -> String {
let mut encoded = form_urlencoded::Serializer::new(String::new());
for (key, value) in x {
match value {
OneOrMany::One(value) => {
encoded.append_pair(&key, &value);
}
OneOrMany::Many(values) => {
for value in values {
encoded.append_pair(&key, &value);
}
}
}
}
encoded.finish()
}