use std::ops::Deref;
use std::borrow::Borrow;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use serde::{Deserialize, Serialize};
pub use super::Url;
#[derive(Debug, Default, Serialize, Deserialize)]
#[repr(transparent)]
#[serde(transparent)]
pub struct UrlBuf(String);
impl UrlBuf {
pub fn new() -> UrlBuf {
UrlBuf(String::new())
}
pub fn as_url(&self) -> &Url {
Url::new(self.0.as_str())
}
pub fn into_arc_url(self) -> Arc<Url> {
Url::from(Arc::from(self.0.into_boxed_str()))
}
pub fn prepend<T: AsRef<Url>>(&mut self, url: T) -> &mut Self {
if self.scheme().is_some() {
return self;
}
let mut url = url.as_ref().to_owned();
let suffix = std::mem::replace(self, UrlBuf::new());
url.append(suffix);
*self = url;
self
}
pub fn append<T: AsRef<Url>>(&mut self, url: T) -> &mut Self {
let url = url.as_ref();
if url.scheme().is_some() {
*self = url.to_owned();
} else {
match (self.ends_with('/'), url.starts_with('/')) {
(true, true) => self.0.push_str(&url[1..]),
(true, false) | (false, true) => self.0.push_str(&*url),
(false, false) => {
self.0.push('/');
self.0.push_str(&*url);
}
}
}
self
}
pub fn extend<T: AsRef<Url>, I: IntoIterator<Item = T>>(&mut self, iter: I) -> &mut Self {
for url in iter.into_iter() {
self.append(url.as_ref());
}
self
}
pub fn make_absolute(&mut self) -> &mut Self {
self.prepend("/");
self
}
pub fn make_relative(&mut self) -> &mut Self {
let relative = self.relative_part();
if relative.len() != self.len() {
*self = UrlBuf::from(relative);
}
self
}
}
impl From<String> for UrlBuf {
fn from(value: String) -> Self {
UrlBuf(value)
}
}
impl From<&str> for UrlBuf {
fn from(value: &str) -> Self {
Url::new(value).to_url_buf()
}
}
impl From<&Url> for UrlBuf {
fn from(value: &Url) -> Self {
value.to_url_buf()
}
}
impl From<&Path> for UrlBuf {
fn from(value: &Path) -> Self {
use std::path::Component;
let mut sane_path = PathBuf::new();
for component in value.components() {
match component {
Component::Prefix(_) | Component::CurDir => continue,
Component::RootDir => sane_path.push(component),
Component::ParentDir => { sane_path.pop(); },
Component::Normal(v) => match v.to_str() {
Some(v) => sane_path.push(v),
None => sane_path.push(v.to_string_lossy().to_string())
}
}
}
let string = sane_path.into_os_string().into_string();
UrlBuf(string.expect("should contain only UTF-8"))
}
}
impl Deref for UrlBuf {
type Target = Url;
fn deref(&self) -> &Self::Target {
self.as_url()
}
}
impl AsRef<Url> for UrlBuf {
fn as_ref(&self) -> &Url {
self.as_url()
}
}
impl Borrow<Url> for UrlBuf {
fn borrow(&self) -> &Url {
self.as_url()
}
}
impl AsRef<str> for UrlBuf {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Borrow<str> for UrlBuf {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl<U: AsRef<Url>> FromIterator<U> for UrlBuf {
fn from_iter<T: IntoIterator<Item = U>>(iter: T) -> Self {
let mut url = UrlBuf::new();
url.extend(iter);
url
}
}
impl From<UrlBuf> for Arc<str> {
fn from(value: UrlBuf) -> Self {
value.into_arc_url().into()
}
}
impl From<UrlBuf> for Arc<Url> {
fn from(value: UrlBuf) -> Self {
value.into_arc_url()
}
}
impl From<UrlBuf> for String {
fn from(value: UrlBuf) -> Self {
value.0
}
}