use std::convert::TryFrom;
use std::error::Error;
use std::ffi::{OsStr, OsString};
use std::fmt::{Debug, Display, Formatter};
use std::path::Path;
#[derive(Debug)]
pub struct InvalidUrl<'a>(&'a str);
impl<'a> Display for InvalidUrl<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "invalid url \"{}\"", self.0)
}
}
impl<'a> Error for InvalidUrl<'a> {}
pub struct Url<'a> {
scheme: &'a str,
path: &'a OsStr,
}
impl<'a> Url<'a> {
pub fn new(scheme: &'a str, path: &'a OsStr) -> Url<'a> {
Url { scheme, path }
}
pub fn scheme(&self) -> &'a str {
self.scheme
}
pub fn path(&self) -> &'a OsStr {
self.path
}
pub fn is_path(&self) -> bool {
self.scheme == "file"
}
pub fn to_os_str(&self) -> std::io::Result<OsString> {
let mut s = OsString::from(self.scheme);
s.push("://");
if self.is_path() {
let path = Path::new(self.path);
if !path.is_absolute() {
let path = crate::fs::get_absolute_path(path)?;
s.push(path);
} else {
s.push(path);
}
} else {
s.push(self.path);
}
Ok(s)
}
}
impl<'a> Display for Url<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}://{}", self.scheme, self.path.to_string_lossy())
}
}
impl<'a> From<&'a Path> for Url<'a> {
fn from(value: &'a Path) -> Self {
Url::new("file", value.as_os_str())
}
}
impl<'a> TryFrom<&'a str> for Url<'a> {
type Error = InvalidUrl<'a>;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
match value.find("://") {
Some(id) => {
let scheme = &value[..id];
let path = &value[id + 3..];
Ok(Url {
scheme,
path: path.as_ref(),
})
}
None => Err(InvalidUrl(value)),
}
}
}