use super::*;
use core::ops::Deref;
#[cfg(feature = "alloc")]
use alloc::string::ToString;
#[derive(Eq, Hash)]
pub struct Uri(UriRef);
_impl_uri_traits_base!(Uri);
impl Deref for Uri {
type Target = UriRef;
fn deref(&self) -> &Self::Target {
self.as_uri_ref()
}
}
impl AsRef<UriRef> for Uri {
fn as_ref(&self) -> &UriRef {
&self.0
}
}
impl AnyUriRef for Uri {
unsafe fn write_to_unsafe<T: core::fmt::Write + ?Sized>(
&self,
write: &mut T,
) -> Result<(), core::fmt::Error> {
write.write_str(self.as_str())
}
fn is_empty(&self) -> bool {
self.0.is_empty()
}
fn uri_type(&self) -> UriType {
if self.0.starts_with("//") {
UriType::NetworkPath
} else {
let i = self.find(':').expect("Uri contract broken");
if self[i..].starts_with("://") {
UriType::Uri
} else if self[i..].starts_with(":/") {
UriType::UriNoAuthority
} else {
UriType::UriCannotBeABase
}
}
}
fn components(&self) -> UriRawComponents<'_> {
self.0.components()
}
}
impl core::fmt::Display for Uri {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.write_to(f)
}
}
impl Uri {
pub fn from_str(input: &str) -> Result<&Uri, ParseError> {
if UriRawComponents::from_str(input)?
.uri_type()
.can_borrow_as_uri()
{
Ok(unsafe { Self::from_str_unchecked(input) })
} else {
Err(ParseError::new("Not a URI", None))
}
}
pub fn is_str_valid<S: AsRef<str>>(s: S) -> bool {
let str_ref = s.as_ref();
if let Ok(components) = UriRawComponents::from_str(str_ref) {
if components.uri_type().can_borrow_as_uri() {
return true;
}
}
false
}
#[inline(always)]
pub const fn as_uri_ref(&self) -> &UriRef {
&self.0
}
#[cfg(feature = "alloc")]
pub fn to_uri_buf(&self) -> UriBuf {
unsafe { UriBuf::from_string_unchecked(self.to_string()) }
}
}
impl Uri {
pub fn split(&self) -> (&Uri, &RelRef) {
let (uri_base, uri_rel) = self.0.split();
(uri_base.unwrap(), uri_rel)
}
}
impl Uri {
pub fn trim_fragment(&self) -> &Uri {
unsafe { Uri::from_str_unchecked(self.0.trim_fragment().as_str()) }
}
pub fn trim_query(&self) -> &Uri {
unsafe { Uri::from_str_unchecked(self.0.trim_query().as_str()) }
}
pub fn trim_path(&self) -> &Uri {
unsafe { Uri::from_str_unchecked(self.0.trim_path().as_str()) }
}
pub fn trim_resource(&self) -> &Uri {
unsafe { Uri::from_str_unchecked(self.0.trim_resource().as_str()) }
}
}
impl Uri {
#[inline(always)]
pub unsafe fn from_str_unchecked(s: &str) -> &Uri {
&*(s as *const str as *const Uri)
}
#[inline(always)]
pub unsafe fn from_str_unchecked_mut(s: &mut str) -> &mut Uri {
&mut *(s as *mut str as *mut Uri)
}
#[inline(always)]
pub unsafe fn as_mut_str(&mut self) -> &mut str {
self.0.as_mut_str()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_uri_type() {
assert_eq!(iuri!("scheme://example").uri_type(), UriType::Uri);
assert_eq!(iuri!("scheme:/example").uri_type(), UriType::UriNoAuthority);
assert_eq!(
iuri!("scheme:example").uri_type(),
UriType::UriCannotBeABase
);
assert_eq!(
iuri!("scheme:example/://not_a_url").uri_type(),
UriType::UriCannotBeABase
);
}
}