use crate::error::{CamelError, Result};
use std::collections::HashMap;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CamelUri {
pub scheme: String,
pub path: String,
pub params: HashMap<String, String>,
raw: String,
}
impl CamelUri {
pub fn parse(s: &str) -> Result<Self> {
let (scheme, rest) = s.split_once(':').ok_or_else(|| CamelError::InvalidUri {
uri: s.to_owned(),
reason: "missing scheme separator ':'".to_owned(),
})?;
if scheme.is_empty() {
return Err(CamelError::InvalidUri {
uri: s.to_owned(),
reason: "empty scheme".to_owned(),
});
}
let (path, query) = match rest.split_once('?') {
Some((p, q)) => (p, Some(q)),
None => (rest, None),
};
let mut params = HashMap::new();
if let Some(q) = query {
for pair in q.split('&').filter(|p| !p.is_empty()) {
match pair.split_once('=') {
Some((k, v)) => {
params.insert(k.to_owned(), v.to_owned());
}
None => {
params.insert(pair.to_owned(), String::new());
}
}
}
}
Ok(Self {
scheme: scheme.to_owned(),
path: path.to_owned(),
params,
raw: s.to_owned(),
})
}
pub fn as_str(&self) -> &str {
&self.raw
}
pub fn get_param(&self, key: &str) -> Option<&str> {
self.params.get(key).map(|s| s.as_str())
}
}
impl std::fmt::Display for CamelUri {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.raw)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_simple_uri() {
let u = CamelUri::parse("direct:foo").expect("parse");
assert_eq!(u.scheme, "direct");
assert_eq!(u.path, "foo");
assert!(u.params.is_empty());
}
#[test]
fn parses_with_params() {
let u = CamelUri::parse("timer:tick?period=1000&fixedRate=true").expect("parse");
assert_eq!(u.scheme, "timer");
assert_eq!(u.path, "tick");
assert_eq!(u.get_param("period"), Some("1000"));
assert_eq!(u.get_param("fixedRate"), Some("true"));
}
#[test]
fn rejects_missing_scheme() {
assert!(CamelUri::parse("no-scheme").is_err());
assert!(CamelUri::parse(":empty-scheme").is_err());
}
}