use crate::shared::MemChr;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
use std::ops::{Deref, DerefMut};
const PATH_SEPARATOR: char = '/';
const SCHEME_SEPARATOR: [u8; 3] = [b':', b'/', b'/'];
#[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Uri(String);
impl Deref for Uri {
type Target = str;
#[inline]
fn deref(&self) -> &str {
&self.0
}
}
impl DerefMut for Uri {
#[inline]
fn deref_mut(&mut self) -> &mut str {
&mut self.0
}
}
impl Display for Uri {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl From<String> for Uri {
#[inline]
fn from(s: String) -> Self {
Uri(s)
}
}
impl From<&str> for Uri {
#[inline]
fn from(s: &str) -> Self {
Uri(s.to_owned())
}
}
impl Uri {
#[inline]
pub fn into_inner(self) -> String {
self.0
}
pub fn parts(&self) -> Option<impl Iterator<Item = &str>> {
let scheme_end = memchr::memmem::find(self.as_bytes(), &SCHEME_SEPARATOR)?;
let scheme = &self[..scheme_end];
let mut rest = &self[scheme_end + 3..];
rest = rest.trim_start_matches(PATH_SEPARATOR);
Some(std::iter::once(scheme).chain(MemChr::split(rest, PATH_SEPARATOR as u8)))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn it_converts_from_str() {
let uri = Uri::from("res://test1");
assert_eq!(uri.to_string(), "res://test1");
}
#[test]
fn it_splits_scheme_and_path() {
let uri = Uri::from("res://test1/test2");
assert_eq!(
uri.parts().unwrap().collect::<Vec<_>>(),
["res", "test1", "test2"]
);
}
#[test]
fn it_splits_empty() {
let uri = Uri::from("");
assert!(uri.parts().is_none());
}
#[test]
fn it_splits_scheme_and_path_with_double_slash() {
let uri = Uri::from("res://test1//test2");
assert_eq!(
uri.parts().unwrap().collect::<Vec<_>>(),
["res", "test1", "test2"]
);
}
#[test]
fn it_splits_scheme_and_path_with_trailing_slash() {
let uri = Uri::from("res://test1/test2/");
assert_eq!(
uri.parts().unwrap().collect::<Vec<_>>(),
["res", "test1", "test2"]
);
}
#[test]
fn it_splits_scheme_and_path_with_leading_slash() {
let uri = Uri::from("res:///test1/test2");
assert_eq!(
uri.parts().unwrap().collect::<Vec<_>>(),
["res", "test1", "test2"]
);
}
}