rust-galmon-web/src/uitools/routing.rs

49 lines
1.4 KiB
Rust

use std::borrow::Cow;
use std::fmt;
pub trait PathFormatter {
fn append(&mut self, component: &str) -> fmt::Result;
}
pub trait Path: Default + fmt::Display + Clone {
fn fmt(&self, f: &mut dyn PathFormatter) -> fmt::Result;
fn parse(path: &str) -> Self;
fn crumbs<F: FnMut(Self)>(&self, mut add: F) {
add(self.clone());
}
}
pub fn next_component(path: &str) -> (Cow<'_, str>, Option<&str>) {
let (next, rem) = match path.find('/') {
None => (path, None),
Some(sep) => (&path[..sep], Some(&path[sep+1..])),
};
(percent_encoding::percent_decode_str(next).decode_utf8_lossy(), rem)
}
// fragment specials plus directory separator
const FRAGMENT_DIR: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`').add(b'/').add(b'%');
struct PathString(String);
impl PathFormatter for PathString {
fn append(&mut self, component: &str) -> fmt::Result {
use std::fmt::Write;
if self.0.is_empty() {
write!(&mut self.0, "{}", percent_encoding::utf8_percent_encode(component, FRAGMENT_DIR))
} else {
write!(&mut self.0, "/{}", percent_encoding::utf8_percent_encode(component, FRAGMENT_DIR))
}
}
}
pub fn make_path<P: Path>(path: &P) -> Result<String, fmt::Error> {
let mut p = PathString(String::new());
Path::fmt(path, &mut p)?;
Ok(p.0)
}
pub fn crumbs<P: Path>(path: &P) -> Vec<P> {
let mut crumbs = Vec::new();
path.crumbs(|crumb| crumbs.push(crumb));
crumbs
}