summaryrefslogtreecommitdiff
path: root/vendor/iri-string/src
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-15 16:37:08 -0600
committermo khan <mo@mokhan.ca>2025-07-17 16:30:22 -0600
commit45df4d0d9b577fecee798d672695fe24ff57fb1b (patch)
tree1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/iri-string/src
parentf94f79608393d4ab127db63cc41668445ef6b243 (diff)
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/iri-string/src')
-rw-r--r--vendor/iri-string/src/build.rs1234
-rw-r--r--vendor/iri-string/src/components.rs267
-rw-r--r--vendor/iri-string/src/components/authority.rs121
-rw-r--r--vendor/iri-string/src/convert.rs291
-rw-r--r--vendor/iri-string/src/format.rs209
-rw-r--r--vendor/iri-string/src/lib.rs159
-rw-r--r--vendor/iri-string/src/mask_password.rs298
-rw-r--r--vendor/iri-string/src/normalize.rs691
-rw-r--r--vendor/iri-string/src/normalize/error.rs26
-rw-r--r--vendor/iri-string/src/normalize/path.rs620
-rw-r--r--vendor/iri-string/src/normalize/pct_case.rs358
-rw-r--r--vendor/iri-string/src/parser.rs6
-rw-r--r--vendor/iri-string/src/parser/char.rs323
-rw-r--r--vendor/iri-string/src/parser/str.rs390
-rw-r--r--vendor/iri-string/src/parser/str/maybe_pct_encoded.rs369
-rw-r--r--vendor/iri-string/src/parser/trusted.rs476
-rw-r--r--vendor/iri-string/src/parser/trusted/authority.rs32
-rw-r--r--vendor/iri-string/src/parser/validate.rs225
-rw-r--r--vendor/iri-string/src/parser/validate/authority.rs296
-rw-r--r--vendor/iri-string/src/parser/validate/path.rs91
-rw-r--r--vendor/iri-string/src/percent_encode.rs378
-rw-r--r--vendor/iri-string/src/raw.rs55
-rw-r--r--vendor/iri-string/src/resolve.rs344
-rw-r--r--vendor/iri-string/src/spec.rs34
-rw-r--r--vendor/iri-string/src/spec/internal.rs58
-rw-r--r--vendor/iri-string/src/template.rs200
-rw-r--r--vendor/iri-string/src/template/components.rs332
-rw-r--r--vendor/iri-string/src/template/context.rs339
-rw-r--r--vendor/iri-string/src/template/error.rs154
-rw-r--r--vendor/iri-string/src/template/expand.rs1039
-rw-r--r--vendor/iri-string/src/template/parser.rs6
-rw-r--r--vendor/iri-string/src/template/parser/char.rs190
-rw-r--r--vendor/iri-string/src/template/parser/validate.rs161
-rw-r--r--vendor/iri-string/src/template/simple_context.rs218
-rw-r--r--vendor/iri-string/src/template/string.rs647
-rw-r--r--vendor/iri-string/src/template/string/owned.rs296
-rw-r--r--vendor/iri-string/src/types.rs224
-rw-r--r--vendor/iri-string/src/types/generic.rs57
-rw-r--r--vendor/iri-string/src/types/generic/absolute.rs728
-rw-r--r--vendor/iri-string/src/types/generic/error.rs70
-rw-r--r--vendor/iri-string/src/types/generic/fragment.rs108
-rw-r--r--vendor/iri-string/src/types/generic/macros.rs1041
-rw-r--r--vendor/iri-string/src/types/generic/normal.rs944
-rw-r--r--vendor/iri-string/src/types/generic/query.rs135
-rw-r--r--vendor/iri-string/src/types/generic/reference.rs697
-rw-r--r--vendor/iri-string/src/types/generic/relative.rs571
-rw-r--r--vendor/iri-string/src/types/iri.rs382
-rw-r--r--vendor/iri-string/src/types/uri.rs115
-rw-r--r--vendor/iri-string/src/validate.rs358
49 files changed, 0 insertions, 16363 deletions
diff --git a/vendor/iri-string/src/build.rs b/vendor/iri-string/src/build.rs
deleted file mode 100644
index 39a57017..00000000
--- a/vendor/iri-string/src/build.rs
+++ /dev/null
@@ -1,1234 +0,0 @@
-//! URI/IRI builder.
-//!
-//! See the documentation of [`Builder`] type.
-
-use core::fmt::{self, Display as _, Write as _};
-use core::marker::PhantomData;
-
-#[cfg(feature = "alloc")]
-use alloc::collections::TryReserveError;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::ToString;
-
-use crate::format::Censored;
-#[cfg(feature = "alloc")]
-use crate::format::{ToDedicatedString, ToStringFallible};
-use crate::normalize::{self, NormalizationMode, PathCharacteristic, PctCaseNormalized};
-use crate::parser::str::{find_split, prior_byte2};
-use crate::parser::validate as parser;
-use crate::spec::Spec;
-use crate::types::{RiAbsoluteStr, RiReferenceStr, RiRelativeStr, RiStr};
-#[cfg(feature = "alloc")]
-use crate::types::{RiAbsoluteString, RiReferenceString, RiRelativeString, RiString};
-use crate::validate::Error;
-
-/// Port builder.
-///
-/// This type is intended to be created by `From` trait implementations, and
-/// to be passed to [`Builder::port`] method.
-#[derive(Debug, Clone)]
-pub struct PortBuilder<'a>(PortBuilderRepr<'a>);
-
-impl Default for PortBuilder<'_> {
- #[inline]
- fn default() -> Self {
- Self(PortBuilderRepr::Empty)
- }
-}
-
-impl From<u8> for PortBuilder<'_> {
- #[inline]
- fn from(v: u8) -> Self {
- Self(PortBuilderRepr::Integer(v.into()))
- }
-}
-
-impl From<u16> for PortBuilder<'_> {
- #[inline]
- fn from(v: u16) -> Self {
- Self(PortBuilderRepr::Integer(v))
- }
-}
-
-impl<'a> From<&'a str> for PortBuilder<'a> {
- #[inline]
- fn from(v: &'a str) -> Self {
- Self(PortBuilderRepr::String(v))
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<'a> From<&'a alloc::string::String> for PortBuilder<'a> {
- #[inline]
- fn from(v: &'a alloc::string::String) -> Self {
- Self(PortBuilderRepr::String(v.as_str()))
- }
-}
-
-/// Internal representation of a port builder.
-#[derive(Debug, Clone, Copy)]
-#[non_exhaustive]
-enum PortBuilderRepr<'a> {
- /// Empty port.
- Empty,
- /// Port as an integer.
- ///
- /// Note that RFC 3986 accepts any number of digits as a port, but
- /// practically (at least in TCP/IP) `u16` is enough.
- Integer(u16),
- /// Port as a string.
- String(&'a str),
-}
-
-/// Userinfo builder.
-///
-/// This type is intended to be created by `From` trait implementations, and
-/// to be passed to [`Builder::userinfo`] method.
-#[derive(Clone)]
-pub struct UserinfoBuilder<'a>(UserinfoRepr<'a>);
-
-impl Default for UserinfoBuilder<'_> {
- #[inline]
- fn default() -> Self {
- Self(UserinfoRepr::None)
- }
-}
-
-impl fmt::Debug for UserinfoBuilder<'_> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut debug = f.debug_struct("UserinfoBuilder");
- if let Some((user, password)) = self.to_user_password() {
- debug.field("user", &user);
- // > Applications should not render as clear text any data after
- // > the first colon (":") character found within a userinfo
- // > subcomponent unless the data after the colon is the empty
- // > string (indicating no password).
- if matches!(password, None | Some("")) {
- debug.field("password", &password);
- } else {
- debug.field("password", &Some(Censored));
- }
- }
- debug.finish()
- }
-}
-
-impl<'a> UserinfoBuilder<'a> {
- /// Decomposes the userinfo into `user` and `password`.
- #[must_use]
- fn to_user_password(&self) -> Option<(&'a str, Option<&'a str>)> {
- match &self.0 {
- UserinfoRepr::None => None,
- UserinfoRepr::Direct(s) => match find_split(s, b':') {
- None => Some((s, None)),
- Some((user, password)) => Some((user, Some(password))),
- },
- UserinfoRepr::UserPass(user, password) => Some((*user, *password)),
- }
- }
-}
-
-impl<'a> From<&'a str> for UserinfoBuilder<'a> {
- #[inline]
- fn from(direct: &'a str) -> Self {
- Self(UserinfoRepr::Direct(direct))
- }
-}
-
-impl<'a> From<(&'a str, &'a str)> for UserinfoBuilder<'a> {
- #[inline]
- fn from((user, password): (&'a str, &'a str)) -> Self {
- Self(UserinfoRepr::UserPass(user, Some(password)))
- }
-}
-
-impl<'a> From<(&'a str, Option<&'a str>)> for UserinfoBuilder<'a> {
- #[inline]
- fn from((user, password): (&'a str, Option<&'a str>)) -> Self {
- Self(UserinfoRepr::UserPass(user, password))
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<'a> From<&'a alloc::string::String> for UserinfoBuilder<'a> {
- #[inline]
- fn from(v: &'a alloc::string::String) -> Self {
- Self::from(v.as_str())
- }
-}
-
-/// Internal representation of a userinfo builder.
-#[derive(Clone, Copy)]
-enum UserinfoRepr<'a> {
- /// Not specified (absent).
- None,
- /// Direct `userinfo` content.
- Direct(&'a str),
- /// User name and password.
- UserPass(&'a str, Option<&'a str>),
-}
-
-/// URI/IRI authority builder.
-#[derive(Default, Debug, Clone)]
-struct AuthorityBuilder<'a> {
- /// Host.
- host: HostRepr<'a>,
- /// Port.
- port: PortBuilder<'a>,
- /// Userinfo.
- userinfo: UserinfoBuilder<'a>,
-}
-
-impl AuthorityBuilder<'_> {
- /// Writes the authority to the given formatter.
- fn fmt_write_to<S: Spec>(&self, f: &mut fmt::Formatter<'_>, normalize: bool) -> fmt::Result {
- match &self.userinfo.0 {
- UserinfoRepr::None => {}
- UserinfoRepr::Direct(userinfo) => {
- if normalize {
- PctCaseNormalized::<S>::new(userinfo).fmt(f)?;
- } else {
- userinfo.fmt(f)?;
- }
- f.write_char('@')?;
- }
- UserinfoRepr::UserPass(user, password) => {
- if normalize {
- PctCaseNormalized::<S>::new(user).fmt(f)?;
- } else {
- f.write_str(user)?;
- }
- if let Some(password) = password {
- f.write_char(':')?;
- if normalize {
- PctCaseNormalized::<S>::new(password).fmt(f)?;
- } else {
- password.fmt(f)?;
- }
- }
- f.write_char('@')?;
- }
- }
-
- match self.host {
- HostRepr::String(host) => {
- if normalize {
- normalize::normalize_host_port::<S>(f, host)?;
- } else {
- f.write_str(host)?;
- }
- }
- #[cfg(feature = "std")]
- HostRepr::IpAddr(ipaddr) => match ipaddr {
- std::net::IpAddr::V4(v) => v.fmt(f)?,
- std::net::IpAddr::V6(v) => write!(f, "[{v}]")?,
- },
- }
-
- match self.port.0 {
- PortBuilderRepr::Empty => {}
- PortBuilderRepr::Integer(v) => write!(f, ":{v}")?,
- PortBuilderRepr::String(v) => {
- // Omit empty port if the normalization is enabled.
- if !(v.is_empty() && normalize) {
- write!(f, ":{v}")?;
- }
- }
- }
-
- Ok(())
- }
-}
-
-/// Host representation.
-#[derive(Debug, Clone, Copy)]
-enum HostRepr<'a> {
- /// Direct string representation.
- String(&'a str),
- #[cfg(feature = "std")]
- /// Dedicated IP address type.
- IpAddr(std::net::IpAddr),
-}
-
-impl Default for HostRepr<'_> {
- #[inline]
- fn default() -> Self {
- Self::String("")
- }
-}
-
-/// URI/IRI reference builder.
-///
-/// # Usage
-///
-/// 1. Create builder by [`Builder::new()`][`Self::new`].
-/// 2. Set (or unset) components and set normalization mode as you wish.
-/// 3. Validate by [`Builder::build()`][`Self::build`] and get [`Built`] value.
-/// 4. Use [`core::fmt::Display`] trait to serialize the resulting [`Built`],
-/// or use [`From`]/[`Into`] traits to convert into an allocated string types.
-///
-/// ```
-/// # use iri_string::validate::Error;
-/// use iri_string::build::Builder;
-/// # #[cfg(not(feature = "alloc"))]
-/// # use iri_string::types::IriStr;
-/// # #[cfg(feature = "alloc")]
-/// use iri_string::types::{IriStr, IriString};
-///
-/// // 1. Create builder.
-/// let mut builder = Builder::new();
-///
-/// // 2. Set (or unset) component and normalization mode.
-/// builder.scheme("http");
-/// builder.host("example.com");
-/// builder.path("/foo/../");
-/// builder.normalize();
-///
-/// // 3. Validate and create the result.
-/// let built = builder.build::<IriStr>()?;
-///
-/// # #[cfg(feature = "alloc")] {
-/// // 4a. Serialize by `Display` trait (or `ToString`).
-/// let s = built.to_string();
-/// assert_eq!(s, "http://example.com/");
-/// # }
-///
-/// # #[cfg(feature = "alloc")] {
-/// // 4b. Convert into an allocated string types.
-/// // Thanks to pre-validation by `.build::<IriStr>()`, this conversion is infallible!
-/// let s: IriString = built.into();
-/// assert_eq!(s, "http://example.com/");
-/// # }
-///
-/// # Ok::<_, Error>(())
-/// ```
-#[derive(Default, Debug, Clone)]
-pub struct Builder<'a> {
- /// Scheme.
- scheme: Option<&'a str>,
- /// Authority.
- authority: Option<AuthorityBuilder<'a>>,
- /// Path.
- path: &'a str,
- /// Query (without the leading `?`).
- query: Option<&'a str>,
- /// Fragment (without the leading `#`).
- fragment: Option<&'a str>,
- /// Normalization mode.
- normalize: bool,
-}
-
-impl<'a> Builder<'a> {
- /// Creates a builder with empty data.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let builder = Builder::new();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Writes the authority to the given formatter.
- ///
- /// Don't expose this as public, since this method does not validate.
- ///
- /// # Preconditions
- ///
- /// The IRI string to be built should be a valid IRI reference.
- /// Callers are responsible to validate the component values before calling
- /// this method.
- fn fmt_write_to<S: Spec>(
- &self,
- f: &mut fmt::Formatter<'_>,
- path_is_absolute: bool,
- ) -> fmt::Result {
- if let Some(scheme) = self.scheme {
- // Write the scheme.
- if self.normalize {
- normalize::normalize_scheme(f, scheme)?;
- } else {
- f.write_str(scheme)?;
- }
- f.write_char(':')?;
- }
-
- if let Some(authority) = &self.authority {
- f.write_str("//")?;
- authority.fmt_write_to::<S>(f, self.normalize)?;
- }
-
- if !self.normalize {
- // No normalization.
- f.write_str(self.path)?;
- } else if self.scheme.is_some() || self.authority.is_some() || path_is_absolute {
- // Apply full syntax-based normalization.
- let op = normalize::NormalizationOp {
- mode: NormalizationMode::Default,
- };
- normalize::PathToNormalize::from_single_path(self.path).fmt_write_normalize::<S, _>(
- f,
- op,
- self.authority.is_some(),
- )?;
- } else {
- // The IRI reference starts with `path` component, and the path is relative.
- // Skip path segment normalization.
- PctCaseNormalized::<S>::new(self.path).fmt(f)?;
- }
-
- if let Some(query) = self.query {
- f.write_char('?')?;
- if self.normalize {
- normalize::normalize_query::<S>(f, query)?;
- } else {
- f.write_str(query)?;
- }
- }
-
- if let Some(fragment) = self.fragment {
- f.write_char('#')?;
- if self.normalize {
- normalize::normalize_fragment::<S>(f, fragment)?;
- } else {
- f.write_str(fragment)?;
- }
- }
-
- Ok(())
- }
-
- /// Builds the proxy object that can be converted to the desired IRI string type.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriStr;
- /// # #[cfg(feature = "alloc")]
- /// use iri_string::types::IriString;
- ///
- /// let mut builder = Builder::new();
- ///
- /// builder.scheme("http");
- /// builder.host("example.com");
- /// builder.path("/foo/bar");
- ///
- /// let built = builder.build::<IriStr>()?;
- ///
- /// # #[cfg(feature = "alloc")] {
- /// // The returned value implements `core::fmt::Display` and
- /// // `core::string::ToString`.
- /// assert_eq!(built.to_string(), "http://example.com/foo/bar");
- ///
- /// // The returned value implements `Into<{iri_owned_string_type}>`.
- /// let iri = IriString::from(built);
- /// // `let iri: IriString = built.into();` is also OK.
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn build<T>(self) -> Result<Built<'a, T>, Error>
- where
- T: ?Sized + Buildable<'a>,
- {
- <T as private::Sealed<'a>>::validate_builder(self)
- }
-}
-
-// Setters does not return `&mut Self` or `Self` since it introduces needless
-// ambiguity for users.
-// For example, if setters return something and allows method chaining, can you
-// correctly explain what happens with the code below without reading document?
-//
-// ```text
-// let mut builder = Builder::new().foo("foo").bar("bar");
-// let baz = builder.baz("baz").clone().build();
-// // Should the result be foo+bar+qux, or foo+bar+baz+qux?
-// let qux = builder.qux("qux").build();
-// ```
-impl<'a> Builder<'a> {
- /// Sets the scheme.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.scheme("foo");
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "foo:");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn scheme(&mut self, v: &'a str) {
- self.scheme = Some(v);
- }
-
- /// Unsets the scheme.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.scheme("foo");
- /// builder.unset_scheme();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn unset_scheme(&mut self) {
- self.scheme = None;
- }
-
- /// Sets the path.
- ///
- /// Note that no methods are provided to "unset" path since every IRI
- /// references has a path component (although it can be empty).
- /// If you want to "unset" the path, just set the empty string.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.path("foo/bar");
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "foo/bar");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn path(&mut self, v: &'a str) {
- self.path = v;
- }
-
- /// Initializes the authority builder.
- #[inline]
- fn authority_builder(&mut self) -> &mut AuthorityBuilder<'a> {
- self.authority.get_or_insert_with(AuthorityBuilder::default)
- }
-
- /// Unsets the authority.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.host("example.com");
- /// builder.unset_authority();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn unset_authority(&mut self) {
- self.authority = None;
- }
-
- /// Sets the userinfo.
- ///
- /// `userinfo` component always have `user` part (but it can be empty).
- ///
- /// Note that `("", None)` is considered as an empty userinfo, rather than
- /// unset userinfo.
- /// Also note that the user part cannot have colon characters.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.userinfo("user:pass");
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "//user:pass@");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// You can specify `(user, password)` pair.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- ///
- /// builder.userinfo(("user", Some("pass")));
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(
- /// builder.clone().build::<IriReferenceStr>()?.to_string(),
- /// "//user:pass@"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// `("", None)` is considered as an empty userinfo.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.userinfo(("", None));
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "//@");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn userinfo<T: Into<UserinfoBuilder<'a>>>(&mut self, v: T) {
- self.authority_builder().userinfo = v.into();
- }
-
- /// Unsets the port.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.userinfo("user:pass");
- /// // Note that this does not unset the entire authority.
- /// // Now empty authority is set.
- /// builder.unset_userinfo();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "//");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn unset_userinfo(&mut self) {
- self.authority_builder().userinfo = UserinfoBuilder::default();
- }
-
- /// Sets the reg-name or IP address (i.e. host) without port.
- ///
- /// Note that no methods are provided to "unset" host.
- /// Depending on your situation, set empty string as a reg-name, or unset
- /// the authority entirely by [`unset_authority`][`Self::unset_authority`]
- /// method.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.host("example.com");
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "//example.com");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn host(&mut self, v: &'a str) {
- self.authority_builder().host = HostRepr::String(v);
- }
-
- /// Sets the IP address as a host.
- ///
- /// Note that no methods are provided to "unset" host.
- /// Depending on your situation, set empty string as a reg-name, or unset
- /// the authority entirely by [`unset_authority`][`Self::unset_authority`]
- /// method.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "std")] {
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.ip_address(std::net::Ipv4Addr::new(192, 0, 2, 0));
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "//192.0.2.0");
- /// # }
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[cfg(feature = "std")]
- #[inline]
- pub fn ip_address<T: Into<std::net::IpAddr>>(&mut self, addr: T) {
- self.authority_builder().host = HostRepr::IpAddr(addr.into());
- }
-
- /// Sets the port.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.port(80_u16);
- /// // Accepts other types that implements `Into<PortBuilder<'a>>`.
- /// //builder.port(80_u8);
- /// //builder.port("80");
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "//:80");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn port<T: Into<PortBuilder<'a>>>(&mut self, v: T) {
- self.authority_builder().port = v.into();
- }
-
- /// Unsets the port.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.port(80_u16);
- /// // Note that this does not unset the entire authority.
- /// // Now empty authority is set.
- /// builder.unset_port();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "//");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn unset_port(&mut self) {
- self.authority_builder().port = PortBuilder::default();
- }
-
- /// Sets the query.
- ///
- /// The string after `?` should be specified.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.query("q=example");
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "?q=example");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn query(&mut self, v: &'a str) {
- self.query = Some(v);
- }
-
- /// Unsets the query.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.query("q=example");
- /// builder.unset_query();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn unset_query(&mut self) {
- self.query = None;
- }
-
- /// Sets the fragment.
- ///
- /// The string after `#` should be specified.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.fragment("anchor");
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "#anchor");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn fragment(&mut self, v: &'a str) {
- self.fragment = Some(v);
- }
-
- /// Unsets the fragment.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.fragment("anchor");
- /// builder.unset_fragment();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn unset_fragment(&mut self) {
- self.fragment = None;
- }
-
- /// Stop normalizing the result.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.scheme("http");
- /// // `%75%73%65%72` is "user".
- /// builder.userinfo("%75%73%65%72");
- /// builder.host("EXAMPLE.COM");
- /// builder.port("");
- /// builder.path("/foo/../%2e%2e/bar/%2e/baz/.");
- ///
- /// builder.unset_normalize();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(
- /// iri.to_string(),
- /// "http://%75%73%65%72@EXAMPLE.COM:/foo/../%2e%2e/bar/%2e/baz/."
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn unset_normalize(&mut self) {
- self.normalize = false;
- }
-
- /// Normalizes the result using RFC 3986 syntax-based normalization and
- /// WHATWG URL Standard algorithm.
- ///
- /// # Normalization
- ///
- /// If `scheme` or `authority` component is present or the path is absolute,
- /// the build result will fully normalized using full syntax-based normalization:
- ///
- /// * case normalization ([RFC 3986 6.2.2.1]),
- /// * percent-encoding normalization ([RFC 3986 6.2.2.2]), and
- /// * path segment normalization ([RFC 3986 6.2.2.2]).
- ///
- /// However, if both `scheme` and `authority` is absent and the path is relative
- /// (including empty), i.e. the IRI reference to be built starts with the
- /// relative `path` component, path segment normalization will be omitted.
- /// This is because the path segment normalization depends on presence or
- /// absense of the `authority` components, and will remove extra `..`
- /// segments which should not be ignored.
- ///
- /// Note that `path` must already be empty or start with a slash **before
- /// the normalizaiton** if `authority` is present.
- ///
- /// # WHATWG URL Standard
- ///
- /// If you need to avoid WHATWG URL Standard serialization, use
- /// [`Built::ensure_rfc3986_normalizable`] method to test if the result is
- /// normalizable without WHATWG spec.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::build::Builder;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let mut builder = Builder::new();
- /// builder.scheme("http");
- /// // `%75%73%65%72` is "user".
- /// builder.userinfo("%75%73%65%72");
- /// builder.host("EXAMPLE.COM");
- /// builder.port("");
- /// builder.path("/foo/../%2e%2e/bar/%2e/baz/.");
- ///
- /// builder.normalize();
- ///
- /// let iri = builder.build::<IriReferenceStr>()?;
- /// # #[cfg(feature = "alloc")] {
- /// assert_eq!(iri.to_string(), "http://user@example.com/bar/baz/");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn normalize(&mut self) {
- self.normalize = true;
- }
-}
-
-/// [`Display`]-able IRI build result.
-///
-/// The value of this type can generate an IRI using [`From`]/[`Into`] traits or
-/// [`Display`] trait.
-///
-/// # Security consideration
-///
-/// This can be stringified or directly printed by `std::fmt::Display`, but note
-/// that this `Display` **does not hide the password part**. Be careful **not to
-/// print the value using `Display for Built<_>` in public context**.
-///
-/// [`From`]: `core::convert::From`
-/// [`Into`]: `core::convert::Into`
-/// [`Display`]: `core::fmt::Display`
-#[derive(Debug)]
-pub struct Built<'a, T: ?Sized> {
- /// Builder with the validated content.
- builder: Builder<'a>,
- /// Whether the path is absolute.
- path_is_absolute: bool,
- /// String type.
- _ty_str: PhantomData<fn() -> T>,
-}
-
-impl<T: ?Sized> Clone for Built<'_, T> {
- #[inline]
- fn clone(&self) -> Self {
- Self {
- builder: self.builder.clone(),
- path_is_absolute: self.path_is_absolute,
- _ty_str: PhantomData,
- }
- }
-}
-
-/// Implements conversions to a string.
-macro_rules! impl_stringifiers {
- ($borrowed:ident, $owned:ident) => {
- impl<S: Spec> Built<'_, $borrowed<S>> {
- /// Returns Ok`(())` if the IRI is normalizable by the RFC 3986 algorithm.
- #[inline]
- pub fn ensure_rfc3986_normalizable(&self) -> Result<(), normalize::Error> {
- if self.builder.authority.is_none() {
- let path = normalize::PathToNormalize::from_single_path(self.builder.path);
- path.ensure_rfc3986_normalizable_with_authority_absent()?;
- }
- Ok(())
- }
- }
-
- impl<S: Spec> fmt::Display for Built<'_, $borrowed<S>> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.builder.fmt_write_to::<S>(f, self.path_is_absolute)
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<S: Spec> ToDedicatedString for Built<'_, $borrowed<S>> {
- type Target = $owned<S>;
-
- #[inline]
- fn try_to_dedicated_string(&self) -> Result<Self::Target, TryReserveError> {
- let s = self.try_to_string()?;
- Ok(TryFrom::try_from(s)
- .expect("[validity] the IRI to be built is already validated"))
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<S: Spec> From<Built<'_, $borrowed<S>>> for $owned<S> {
- #[inline]
- fn from(builder: Built<'_, $borrowed<S>>) -> Self {
- (&builder).into()
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<S: Spec> From<&Built<'_, $borrowed<S>>> for $owned<S> {
- #[inline]
- fn from(builder: &Built<'_, $borrowed<S>>) -> Self {
- let s = builder.to_string();
- Self::try_from(s).expect("[validity] the IRI to be built is already validated")
- }
- }
- };
-}
-
-impl_stringifiers!(RiReferenceStr, RiReferenceString);
-impl_stringifiers!(RiStr, RiString);
-impl_stringifiers!(RiAbsoluteStr, RiAbsoluteString);
-impl_stringifiers!(RiRelativeStr, RiRelativeString);
-
-/// A trait for borrowed IRI string types buildable by the [`Builder`].
-pub trait Buildable<'a>: private::Sealed<'a> {}
-
-impl<'a, S: Spec> private::Sealed<'a> for RiReferenceStr<S> {
- fn validate_builder(builder: Builder<'a>) -> Result<Built<'a, Self>, Error> {
- let path_is_absolute = validate_builder_for_iri_reference::<S>(&builder)?;
-
- Ok(Built {
- builder,
- path_is_absolute,
- _ty_str: PhantomData,
- })
- }
-}
-impl<S: Spec> Buildable<'_> for RiReferenceStr<S> {}
-
-impl<'a, S: Spec> private::Sealed<'a> for RiStr<S> {
- fn validate_builder(builder: Builder<'a>) -> Result<Built<'a, Self>, Error> {
- if builder.scheme.is_none() {
- return Err(Error::new());
- }
- let path_is_absolute = validate_builder_for_iri_reference::<S>(&builder)?;
-
- Ok(Built {
- builder,
- path_is_absolute,
- _ty_str: PhantomData,
- })
- }
-}
-impl<S: Spec> Buildable<'_> for RiStr<S> {}
-
-impl<'a, S: Spec> private::Sealed<'a> for RiAbsoluteStr<S> {
- fn validate_builder(builder: Builder<'a>) -> Result<Built<'a, Self>, Error> {
- if builder.scheme.is_none() {
- return Err(Error::new());
- }
- if builder.fragment.is_some() {
- return Err(Error::new());
- }
- let path_is_absolute = validate_builder_for_iri_reference::<S>(&builder)?;
-
- Ok(Built {
- builder,
- path_is_absolute,
- _ty_str: PhantomData,
- })
- }
-}
-impl<S: Spec> Buildable<'_> for RiAbsoluteStr<S> {}
-
-impl<'a, S: Spec> private::Sealed<'a> for RiRelativeStr<S> {
- fn validate_builder(builder: Builder<'a>) -> Result<Built<'a, Self>, Error> {
- if builder.scheme.is_some() {
- return Err(Error::new());
- }
- let path_is_absolute = validate_builder_for_iri_reference::<S>(&builder)?;
-
- Ok(Built {
- builder,
- path_is_absolute,
- _ty_str: PhantomData,
- })
- }
-}
-impl<S: Spec> Buildable<'_> for RiRelativeStr<S> {}
-
-/// Checks whether the builder output is valid IRI reference.
-///
-/// Returns whether the path is absolute.
-fn validate_builder_for_iri_reference<S: Spec>(builder: &Builder<'_>) -> Result<bool, Error> {
- if let Some(scheme) = builder.scheme {
- parser::validate_scheme(scheme)?;
- }
-
- if let Some(authority) = &builder.authority {
- match &authority.userinfo.0 {
- UserinfoRepr::None => {}
- UserinfoRepr::Direct(userinfo) => {
- parser::validate_userinfo::<S>(userinfo)?;
- }
- UserinfoRepr::UserPass(user, password) => {
- // `user` is not allowed to have a colon, since the characters
- // after the colon is parsed as the password.
- if user.contains(':') {
- return Err(Error::new());
- }
-
- // Note that the syntax of components inside `authority`
- // (`user` and `password`) is not specified by RFC 3986.
- parser::validate_userinfo::<S>(user)?;
- if let Some(password) = password {
- parser::validate_userinfo::<S>(password)?;
- }
- }
- }
-
- match authority.host {
- HostRepr::String(s) => parser::validate_host::<S>(s)?,
- #[cfg(feature = "std")]
- HostRepr::IpAddr(_) => {}
- }
-
- if let PortBuilderRepr::String(s) = authority.port.0 {
- if !s.bytes().all(|b| b.is_ascii_digit()) {
- return Err(Error::new());
- }
- }
- }
-
- let path_is_absolute: bool;
- let mut is_path_acceptable;
- if builder.normalize {
- if builder.scheme.is_some() || builder.authority.is_some() || builder.path.starts_with('/')
- {
- if builder.authority.is_some() {
- // Note that the path should already be in an absolute form before normalization.
- is_path_acceptable = builder.path.is_empty() || builder.path.starts_with('/');
- } else {
- is_path_acceptable = true;
- }
- let op = normalize::NormalizationOp {
- mode: NormalizationMode::Default,
- };
- let path_characteristic = PathCharacteristic::from_path_to_display::<S>(
- &normalize::PathToNormalize::from_single_path(builder.path),
- op,
- builder.authority.is_some(),
- );
- path_is_absolute = path_characteristic.is_absolute();
- is_path_acceptable = is_path_acceptable
- && match path_characteristic {
- PathCharacteristic::CommonAbsolute | PathCharacteristic::CommonRelative => true,
- PathCharacteristic::StartsWithDoubleSlash
- | PathCharacteristic::RelativeFirstSegmentHasColon => {
- builder.scheme.is_some() || builder.authority.is_some()
- }
- };
- } else {
- path_is_absolute = false;
- // If the path is relative (where neither scheme nor authority is
- // available), the first segment should not contain a colon.
- is_path_acceptable = prior_byte2(builder.path.as_bytes(), b'/', b':') != Some(b':');
- }
- } else {
- path_is_absolute = builder.path.starts_with('/');
- is_path_acceptable = if builder.authority.is_some() {
- // The path should be absolute or empty.
- path_is_absolute || builder.path.is_empty()
- } else if builder.scheme.is_some() || path_is_absolute {
- // The path should not start with '//'.
- !builder.path.starts_with("//")
- } else {
- // If the path is relative (where neither scheme nor authority is
- // available), the first segment should not contain a colon.
- prior_byte2(builder.path.as_bytes(), b'/', b':') != Some(b':')
- };
- }
- if !is_path_acceptable {
- return Err(Error::new());
- }
-
- if let Some(query) = builder.query {
- parser::validate_query::<S>(query)?;
- }
-
- if let Some(fragment) = builder.fragment {
- parser::validate_fragment::<S>(fragment)?;
- }
-
- Ok(path_is_absolute)
-}
-
-/// Private module to put the trait to seal.
-mod private {
- use super::{Builder, Built, Error};
-
- /// A trait for types buildable by the [`Builder`].
- pub trait Sealed<'a> {
- /// Validates the content of the builder and returns the validated type if possible.
- fn validate_builder(builder: Builder<'a>) -> Result<Built<'a, Self>, Error>;
- }
-}
diff --git a/vendor/iri-string/src/components.rs b/vendor/iri-string/src/components.rs
deleted file mode 100644
index 33e7ac45..00000000
--- a/vendor/iri-string/src/components.rs
+++ /dev/null
@@ -1,267 +0,0 @@
-//! Components of IRIs.
-
-mod authority;
-
-use core::num::NonZeroUsize;
-use core::ops::{Range, RangeFrom, RangeTo};
-
-use crate::parser::trusted as trusted_parser;
-use crate::spec::Spec;
-use crate::types::RiReferenceStr;
-
-pub use self::authority::AuthorityComponents;
-
-/// Positions to split an IRI into components.
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct Splitter {
- /// Scheme end.
- scheme_end: Option<NonZeroUsize>,
- /// Authority end.
- ///
- /// Note that absence of the authority and the empty authority is
- /// distinguished.
- authority_end: Option<NonZeroUsize>,
- /// Query start (after the leading `?`).
- query_start: Option<NonZeroUsize>,
- /// Fragment start (after the leading `#`).
- fragment_start: Option<NonZeroUsize>,
-}
-
-impl Splitter {
- /// Creates a new splitter.
- #[inline]
- #[must_use]
- pub(crate) fn new(
- scheme_end: Option<NonZeroUsize>,
- authority_end: Option<NonZeroUsize>,
- query_start: Option<NonZeroUsize>,
- fragment_start: Option<NonZeroUsize>,
- ) -> Self {
- Self {
- scheme_end,
- authority_end,
- query_start,
- fragment_start,
- }
- }
-
- /// Decomposes an IRI into five major components: scheme, authority, path, query, and fragment.
- #[must_use]
- fn split_into_major(
- self,
- s: &str,
- ) -> (Option<&str>, Option<&str>, &str, Option<&str>, Option<&str>) {
- let (scheme, next_of_scheme) = match self.scheme_end {
- // +1: ":".len()
- Some(end) => (Some(&s[..end.get()]), end.get() + 1),
- None => (None, 0),
- };
- let (authority, next_of_authority) = match self.authority_end {
- // +2: "//".len()
- Some(end) => (Some(&s[(next_of_scheme + 2)..end.get()]), end.get()),
- None => (None, next_of_scheme),
- };
- let (fragment, end_of_prev_of_fragment) = match self.fragment_start {
- // -1: "#".len()
- Some(start) => (Some(&s[start.get()..]), start.get() - 1),
- None => (None, s.len()),
- };
- let (query, end_of_path) = match self.query_start {
- Some(start) => (
- Some(&s[start.get()..end_of_prev_of_fragment]),
- // -1: "?".len()
- start.get() - 1,
- ),
- None => (None, end_of_prev_of_fragment),
- };
- let path = &s[next_of_authority..end_of_path];
- (scheme, authority, path, query, fragment)
- }
-
- /// Returns the range for the scheme part.
- #[inline]
- #[must_use]
- fn scheme_range(self) -> Option<RangeTo<usize>> {
- self.scheme_end.map(|end| ..end.get())
- }
-
- /// Returns the scheme as a string.
- #[inline]
- #[must_use]
- pub(crate) fn scheme_str<'a>(&self, s: &'a str) -> Option<&'a str> {
- self.scheme_range().map(|range| &s[range])
- }
-
- /// Returns true if the IRI has a scheme part, false otherwise.
- #[inline]
- #[must_use]
- pub(crate) fn has_scheme(&self) -> bool {
- self.scheme_end.is_some()
- }
-
- /// Returns the range for the authority part.
- #[inline]
- #[must_use]
- fn authority_range(self) -> Option<Range<usize>> {
- let end = self.authority_end?.get();
- // 2: "//".len()
- // +3: "://".len()
- let start = self.scheme_end.map_or(2, |v| v.get() + 3);
- Some(start..end)
- }
-
- /// Returns the authority as a string.
- #[inline]
- #[must_use]
- pub(crate) fn authority_str<'a>(&self, s: &'a str) -> Option<&'a str> {
- self.authority_range().map(|range| &s[range])
- }
-
- /// Returns true if the IRI has an authority part, false otherwise.
- #[inline]
- #[must_use]
- pub(crate) fn has_authority(&self) -> bool {
- self.authority_end.is_some()
- }
-
- /// Returns the range for the path part.
- #[inline]
- #[must_use]
- fn path_range(self, full_len: usize) -> Range<usize> {
- // -1: "?".len() and "#".len()
- let end = self
- .query_start
- .or(self.fragment_start)
- .map_or(full_len, |v| v.get() - 1);
- let start = self.authority_end.map_or_else(
- // +1: ":".len()
- || self.scheme_end.map_or(0, |v| v.get() + 1),
- NonZeroUsize::get,
- );
-
- start..end
- }
-
- /// Returns the path as a string.
- #[inline]
- #[must_use]
- pub(crate) fn path_str<'a>(&self, s: &'a str) -> &'a str {
- &s[self.path_range(s.len())]
- }
-
- /// Returns true if the path part of the IRI is empty.
- #[inline]
- #[must_use]
- pub(crate) fn is_path_empty(&self, full_len: usize) -> bool {
- self.path_range(full_len).is_empty()
- }
-
- /// Returns the range for the query part excluding a prefix `?`.
- #[inline]
- #[must_use]
- fn query_range(self, full_len: usize) -> Option<Range<usize>> {
- let start = self.query_start?.get();
- // -1: "#".len()
- let end = self.fragment_start.map_or(full_len, |v| v.get() - 1);
-
- Some(start..end)
- }
-
- /// Returns the query as a string.
- #[inline]
- #[must_use]
- pub(crate) fn query_str<'a>(&self, s: &'a str) -> Option<&'a str> {
- self.query_range(s.len()).map(|range| &s[range])
- }
-
- /// Returns true if the IRI has a query part, false otherwise.
- #[inline]
- #[must_use]
- pub(crate) fn has_query(&self) -> bool {
- self.query_start.is_some()
- }
-
- /// Returns the range for the fragment part excluding a prefix `#`.
- #[inline]
- #[must_use]
- pub(crate) fn fragment_range(self) -> Option<RangeFrom<usize>> {
- self.fragment_start.map(|v| v.get()..)
- }
-
- /// Returns the fragment as a string.
- #[inline]
- #[must_use]
- pub(crate) fn fragment_str<'a>(&self, s: &'a str) -> Option<&'a str> {
- self.fragment_range().map(|range| &s[range])
- }
-}
-
-/// Components of an IRI reference.
-///
-/// See <https://tools.ietf.org/html/rfc3986#section-5.2.2>.
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct RiReferenceComponents<'a, S: Spec> {
- /// Original complete string.
- pub(crate) iri: &'a RiReferenceStr<S>,
- /// Positions to split the IRI into components.
- pub(crate) splitter: Splitter,
-}
-
-impl<'a, S: Spec> RiReferenceComponents<'a, S> {
- /// Returns five major components: scheme, authority, path, query, and fragment.
- #[inline]
- #[must_use]
- pub(crate) fn to_major(
- self,
- ) -> (
- Option<&'a str>,
- Option<&'a str>,
- &'a str,
- Option<&'a str>,
- Option<&'a str>,
- ) {
- self.splitter.split_into_major(self.iri.as_str())
- }
-
- /// Returns the IRI reference.
- #[inline]
- #[must_use]
- pub(crate) fn iri(&self) -> &'a RiReferenceStr<S> {
- self.iri
- }
-
- /// Returns the scheme as a string.
- #[inline]
- #[must_use]
- pub(crate) fn scheme_str(&self) -> Option<&str> {
- self.splitter.scheme_str(self.iri.as_str())
- }
-
- /// Returns the authority as a string.
- #[inline]
- #[must_use]
- pub(crate) fn authority_str(&self) -> Option<&str> {
- self.splitter.authority_str(self.iri.as_str())
- }
-
- /// Returns the path as a string.
- #[inline]
- #[must_use]
- pub(crate) fn path_str(&self) -> &str {
- self.splitter.path_str(self.iri.as_str())
- }
-
- /// Returns the query as a string.
- #[inline]
- #[must_use]
- pub(crate) fn query_str(&self) -> Option<&str> {
- self.splitter.query_str(self.iri.as_str())
- }
-}
-
-impl<'a, S: Spec> From<&'a RiReferenceStr<S>> for RiReferenceComponents<'a, S> {
- #[inline]
- fn from(s: &'a RiReferenceStr<S>) -> Self {
- trusted_parser::decompose_iri_reference(s)
- }
-}
diff --git a/vendor/iri-string/src/components/authority.rs b/vendor/iri-string/src/components/authority.rs
deleted file mode 100644
index a7f17744..00000000
--- a/vendor/iri-string/src/components/authority.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-//! Subcomponents of authority.
-
-use crate::parser::trusted as trusted_parser;
-use crate::spec::Spec;
-use crate::types::RiReferenceStr;
-
-/// Subcomponents of authority.
-///
-/// This is a return type of the `authority_components` method of the string
-/// types (for example [`RiStr::authority_components`].
-///
-/// [`RiStr::authority_components`]: `crate::types::RiStr::authority_components`
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct AuthorityComponents<'a> {
- /// Authority string, excluding the leading `//`.
- pub(crate) authority: &'a str,
- /// Start position of the `host`.
- pub(crate) host_start: usize,
- /// End position of the `host`.
- pub(crate) host_end: usize,
-}
-
-impl<'a> AuthorityComponents<'a> {
- /// Creates a new `AuthorityComponents` from the IRI.
- pub fn from_iri<S: Spec>(iri: &'a RiReferenceStr<S>) -> Option<Self> {
- iri.authority_str()
- .map(trusted_parser::authority::decompose_authority)
- }
-
- /// Returns the `userinfo` part, excluding the following `@`.
- #[must_use]
- pub fn userinfo(&self) -> Option<&'a str> {
- let userinfo_at = self.host_start.checked_sub(1)?;
- debug_assert_eq!(self.authority.as_bytes()[userinfo_at], b'@');
- Some(&self.authority[..userinfo_at])
- }
-
- /// Returns the `host` part.
- #[inline]
- #[must_use]
- pub fn host(&self) -> &'a str {
- // NOTE: RFC 6874 support may need the internal logic to change.
- &self.authority[self.host_start..self.host_end]
- }
-
- /// Returns the `port` part, excluding the following `:`.
- #[must_use]
- pub fn port(&self) -> Option<&'a str> {
- if self.host_end == self.authority.len() {
- return None;
- }
- let port_colon = self.host_end;
- debug_assert_eq!(self.authority.as_bytes()[port_colon], b':');
- Some(&self.authority[(port_colon + 1)..])
- }
-}
-
-#[cfg(test)]
-#[cfg(feature = "alloc")]
-mod tests {
- use super::*;
-
- #[cfg(all(feature = "alloc", not(feature = "std")))]
- use alloc::string::String;
-
- use crate::types::IriReferenceStr;
-
- const USERINFO: &[&str] = &["", "user:password", "user"];
-
- const PORT: &[&str] = &[
- "",
- "0",
- "0000",
- "80",
- "1234567890123456789012345678901234567890",
- ];
-
- const HOST: &[&str] = &[
- "",
- "localhost",
- "example.com",
- "192.0.2.0",
- "[2001:db8::1]",
- "[2001:0db8:0:0:0:0:0:1]",
- "[2001:0db8::192.0.2.255]",
- "[v9999.this-is-futuristic-ip-address]",
- ];
-
- fn compose_to_relative_iri(userinfo: Option<&str>, host: &str, port: Option<&str>) -> String {
- let mut buf = String::from("//");
- if let Some(userinfo) = userinfo {
- buf.push_str(userinfo);
- buf.push('@');
- }
- buf.push_str(host);
- if let Some(port) = port {
- buf.push(':');
- buf.push_str(port);
- }
- buf
- }
-
- #[test]
- fn test_decompose_authority() {
- for host in HOST.iter().copied() {
- for userinfo in USERINFO.iter().map(|s| Some(*s)).chain(None) {
- for port in PORT.iter().map(|s| Some(*s)).chain(None) {
- let authority = compose_to_relative_iri(userinfo, host, port);
- let authority =
- IriReferenceStr::new(&authority).expect("test case should be valid");
- let components = AuthorityComponents::from_iri(authority)
- .expect("relative path composed for this test should contain authority");
-
- assert_eq!(components.host(), host);
- assert_eq!(components.userinfo(), userinfo);
- assert_eq!(components.port(), port);
- }
- }
- }
- }
-}
diff --git a/vendor/iri-string/src/convert.rs b/vendor/iri-string/src/convert.rs
deleted file mode 100644
index 5b4ec9a4..00000000
--- a/vendor/iri-string/src/convert.rs
+++ /dev/null
@@ -1,291 +0,0 @@
-//! Conversion between URI/IRI types.
-
-use core::fmt;
-
-#[cfg(feature = "alloc")]
-use alloc::collections::TryReserveError;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-
-#[cfg(feature = "alloc")]
-use crate::format::{ToDedicatedString, ToStringFallible};
-use crate::spec::Spec;
-use crate::types::{
- RiAbsoluteStr, RiFragmentStr, RiQueryStr, RiReferenceStr, RiRelativeStr, RiStr,
-};
-#[cfg(feature = "alloc")]
-use crate::types::{
- RiAbsoluteString, RiFragmentString, RiQueryString, RiReferenceString, RiRelativeString,
- RiString,
-};
-#[cfg(feature = "alloc")]
-use crate::types::{
- UriAbsoluteString, UriFragmentString, UriQueryString, UriReferenceString, UriRelativeString,
- UriString,
-};
-
-/// Hexadecimal digits for a nibble.
-const HEXDIGITS: [u8; 16] = [
- b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F',
-];
-
-/// A resource identifier mapped to a URI of some kind.
-///
-/// Supported `Src` type are:
-///
-/// * IRIs:
-/// + [`IriAbsoluteStr`] (alias of `RiAbsoluteStr<IriSpec>`)
-/// + [`IriReferenceStr`] (alias of `RiReferenceStr<IriSpec>`)
-/// + [`IriRelativeStr`] (alias of `RiRelativeStr<IriSpec>`)
-/// + [`IriStr`] (alias of `RiStr<IriSpec>`)
-/// * URIs:
-/// + [`UriAbsoluteStr`] (alias of `RiAbsoluteStr<UriSpec>`)
-/// + [`UriReferenceStr`] (alias of `RiReferenceStr<UriSpec>`)
-/// + [`UriRelativeStr`] (alias of `RiRelativeStr<UriSpec>`)
-/// + [`UriStr`] (alias of `RiStr<UriSpec>`)
-///
-/// # Examples
-///
-/// ```
-/// use iri_string::convert::MappedToUri;
-/// use iri_string::types::{IriStr, UriStr};
-///
-/// let src = IriStr::new("http://example.com/?alpha=\u{03B1}")?;
-/// // The type is `MappedToUri<IriStr>`, but you usually don't need to specify.
-/// let mapped = MappedToUri::from(src).to_string();
-/// assert_eq!(mapped, "http://example.com/?alpha=%CE%B1");
-/// # Ok::<_, iri_string::validate::Error>(())
-/// ```
-///
-/// [`IriAbsoluteStr`]: crate::types::IriAbsoluteStr
-/// [`IriReferenceStr`]: crate::types::IriReferenceStr
-/// [`IriRelativeStr`]: crate::types::IriRelativeStr
-/// [`IriStr`]: crate::types::IriStr
-/// [`UriAbsoluteStr`]: crate::types::UriAbsoluteStr
-/// [`UriReferenceStr`]: crate::types::UriReferenceStr
-/// [`UriRelativeStr`]: crate::types::UriRelativeStr
-/// [`UriStr`]: crate::types::UriStr
-#[derive(Debug, Clone, Copy)]
-pub struct MappedToUri<'a, Src: ?Sized>(&'a Src);
-
-/// Implement conversions for an IRI string type.
-macro_rules! impl_for_iri {
- ($borrowed:ident, $owned:ident, $owned_uri:ident) => {
- impl<S: Spec> fmt::Display for MappedToUri<'_, $borrowed<S>> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write_percent_encoded(f, self.0.as_str())
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<S: Spec> ToDedicatedString for MappedToUri<'_, $borrowed<S>> {
- type Target = $owned_uri;
-
- fn try_to_dedicated_string(&self) -> Result<Self::Target, TryReserveError> {
- let s = self.try_to_string()?;
- Ok(TryFrom::try_from(s)
- .expect("[validity] the IRI must be encoded into a valid URI"))
- }
- }
-
- impl<'a, S: Spec> From<&'a $borrowed<S>> for MappedToUri<'a, $borrowed<S>> {
- #[inline]
- fn from(iri: &'a $borrowed<S>) -> Self {
- Self(iri)
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<'a, S: Spec> From<&'a $owned<S>> for MappedToUri<'a, $borrowed<S>> {
- #[inline]
- fn from(iri: &'a $owned<S>) -> Self {
- Self(iri.as_slice())
- }
- }
- };
-}
-
-impl_for_iri!(RiReferenceStr, RiReferenceString, UriReferenceString);
-impl_for_iri!(RiStr, RiString, UriString);
-impl_for_iri!(RiAbsoluteStr, RiAbsoluteString, UriAbsoluteString);
-impl_for_iri!(RiRelativeStr, RiRelativeString, UriRelativeString);
-impl_for_iri!(RiQueryStr, RiQueryString, UriQueryString);
-impl_for_iri!(RiFragmentStr, RiFragmentString, UriFragmentString);
-
-/// Percent-encodes and writes the IRI string using the given buffer.
-fn write_percent_encoded(f: &mut fmt::Formatter<'_>, mut s: &str) -> fmt::Result {
- while !s.is_empty() {
- // Skip ASCII characters.
- let non_ascii_pos = s.bytes().position(|b| !b.is_ascii()).unwrap_or(s.len());
- let (ascii, rest) = s.split_at(non_ascii_pos);
- if !ascii.is_empty() {
- f.write_str(ascii)?;
- s = rest;
- }
-
- if s.is_empty() {
- return Ok(());
- }
-
- // Search for the next ASCII character.
- let nonascii_end = s.bytes().position(|b| b.is_ascii()).unwrap_or(s.len());
- let (nonasciis, rest) = s.split_at(nonascii_end);
- debug_assert!(
- !nonasciis.is_empty(),
- "string without non-ASCII characters should have caused early return"
- );
- s = rest;
-
- // Escape non-ASCII characters as percent-encoded bytes.
- //
- // RFC 3987 (section 3.1 step 2) says "for each character in
- // 'ucschar' or 'iprivate'", but this simply means "for each
- // non-ASCII characters" since any non-ASCII characters that can
- // appear in an IRI match `ucschar` or `iprivate`.
- /// Number of source bytes to encode at once.
- const NUM_BYTES_AT_ONCE: usize = 21;
- percent_encode_bytes(f, nonasciis, &mut [0_u8; NUM_BYTES_AT_ONCE * 3])?;
- }
-
- Ok(())
-}
-
-/// Percent-encode the string and pass the encoded chunks to the given function.
-///
-/// `buf` is used as a temporary working buffer. It is initialized by this
-/// function, so users can pass any mutable byte slice with enough size.
-///
-/// # Precondition
-///
-/// The length of `buf` must be 3 bytes or more.
-fn percent_encode_bytes(f: &mut fmt::Formatter<'_>, s: &str, buf: &mut [u8]) -> fmt::Result {
- /// Fill the buffer by percent-encoded bytes.
- ///
- /// Note that this function applies percent-encoding to every characters,
- /// even if it is ASCII alphabet.
- ///
- /// # Precondition
- ///
- /// * The length of `buf` must be 3 bytes or more.
- /// * All of the `buf[i * 3]` elements should already be set to `b'%'`.
- // This function have many preconditions and I don't want checks for them
- // to be mandatory, so make this nested inner function.
- fn fill_by_percent_encoded<'a>(buf: &'a mut [u8], bytes: &mut core::str::Bytes<'_>) -> &'a str {
- let src_len = bytes.len();
- // `<[u8; N]>::array_chunks_mut` is unstable as of Rust 1.58.1.
- for (dest, byte) in buf.chunks_exact_mut(3).zip(bytes.by_ref()) {
- debug_assert_eq!(
- dest.len(),
- 3,
- "[validity] `chunks_exact()` must return a slice with the exact length"
- );
- debug_assert_eq!(
- dest[0], b'%',
- "[precondition] the buffer must be properly initialized"
- );
-
- let upper = byte >> 4;
- let lower = byte & 0b1111;
- dest[1] = HEXDIGITS[usize::from(upper)];
- dest[2] = HEXDIGITS[usize::from(lower)];
- }
- let num_dest_written = (src_len - bytes.len()) * 3;
- let buf_filled = &buf[..num_dest_written];
- // SAFETY: `b'%'` and `HEXDIGITS[_]` are all ASCII characters, so
- // `buf_filled` is filled with ASCII characters and is valid UTF-8 bytes.
- unsafe {
- debug_assert!(core::str::from_utf8(buf_filled).is_ok());
- core::str::from_utf8_unchecked(buf_filled)
- }
- }
-
- assert!(
- buf.len() >= 3,
- "[precondition] length of `buf` must be 3 bytes or more"
- );
-
- // Drop the elements that will never be used.
- // The length to be used is always a multiple of three.
- let buf_len = buf.len() / 3 * 3;
- let buf = &mut buf[..buf_len];
-
- // Fill some bytes with `%`.
- // This will be vectorized by optimization (especially for long buffers),
- // so no need to selectively set `buf[i * 3]`.
- buf.fill(b'%');
-
- let mut bytes = s.bytes();
- // `<core::str::Bytes as ExactSizeIterator>::is_empty` is unstable as of Rust 1.58.1.
- while bytes.len() != 0 {
- let encoded = fill_by_percent_encoded(buf, &mut bytes);
- f.write_str(encoded)?;
- }
-
- Ok(())
-}
-
-/// Percent-encodes the given IRI using the given buffer.
-#[cfg(feature = "alloc")]
-pub(crate) fn try_percent_encode_iri_inline(
- iri: &mut String,
-) -> Result<(), alloc::collections::TryReserveError> {
- // Calculate the result length and extend the buffer.
- let num_nonascii = count_nonascii(iri);
- if num_nonascii == 0 {
- // No need to escape.
- return Ok(());
- }
- let additional = num_nonascii * 2;
- iri.try_reserve(additional)?;
- let src_len = iri.len();
-
- // Temporarily take the ownership of the internal buffer.
- let mut buf = core::mem::take(iri).into_bytes();
- // `b'\0'` cannot appear in a valid IRI, so this default value would be
- // useful in case of debugging.
- buf.extend(core::iter::repeat(b'\0').take(additional));
-
- // Fill the buffer from the tail to the head.
- let mut dest_end = buf.len();
- let mut src_end = src_len;
- let mut rest_nonascii = num_nonascii;
- while rest_nonascii > 0 {
- debug_assert!(
- src_end > 0,
- "[validity] the source position should not overrun"
- );
- debug_assert!(
- dest_end > 0,
- "[validity] the destination position should not overrun"
- );
- src_end -= 1;
- dest_end -= 1;
- let byte = buf[src_end];
- if byte.is_ascii() {
- buf[dest_end] = byte;
- // Use the ASCII character directly.
- } else {
- // Percent-encode the byte.
- dest_end -= 2;
- buf[dest_end] = b'%';
- let upper = byte >> 4;
- let lower = byte & 0b1111;
- buf[dest_end + 1] = HEXDIGITS[usize::from(upper)];
- buf[dest_end + 2] = HEXDIGITS[usize::from(lower)];
- rest_nonascii -= 1;
- }
- }
-
- // Move the result from the temporary buffer to the destination.
- let s = String::from_utf8(buf).expect("[consistency] the encoding result is an ASCII string");
- *iri = s;
- Ok(())
-}
-
-/// Returns the number of non-ASCII characters.
-#[cfg(feature = "alloc")]
-#[inline]
-#[must_use]
-fn count_nonascii(s: &str) -> usize {
- s.bytes().filter(|b| !b.is_ascii()).count()
-}
diff --git a/vendor/iri-string/src/format.rs b/vendor/iri-string/src/format.rs
deleted file mode 100644
index ecc038d0..00000000
--- a/vendor/iri-string/src/format.rs
+++ /dev/null
@@ -1,209 +0,0 @@
-//! Utilities for formatting (especially `Display` trait).
-//!
-//! This module contains utilities for [`Display`][`core::fmt::Display`]-able
-//! types.
-
-use core::fmt::{self, Write as _};
-
-#[cfg(feature = "alloc")]
-use alloc::collections::TryReserveError;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-
-/// Output buffer capacity overflow error.
-#[derive(Debug, Clone, Copy)]
-pub struct CapacityOverflowError;
-
-impl fmt::Display for CapacityOverflowError {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("buffer capacity overflow")
- }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for CapacityOverflowError {}
-
-/// Writer to the bytes buffer.
-struct ByteBufWriter<'b> {
- /// Destination buffer.
- buffer: &'b mut [u8],
- /// Position to write the next string fragment.
- cursor: usize,
-}
-
-impl fmt::Write for ByteBufWriter<'_> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- let dest = &mut self.buffer[self.cursor..];
- if dest.len() < s.len() {
- return Err(fmt::Error);
- }
- dest[..s.len()].copy_from_slice(s.as_bytes());
- self.cursor += s.len();
- Ok(())
- }
-}
-
-/// Writes to the bytes buffer.
-pub fn write_to_slice<'a, T: fmt::Display>(
- buf: &'a mut [u8],
- value: &T,
-) -> Result<&'a str, CapacityOverflowError> {
- let mut writer = ByteBufWriter {
- buffer: buf,
- cursor: 0,
- };
- if write!(writer, "{}", value).is_err() {
- return Err(CapacityOverflowError);
- }
- let len = writer.cursor;
- let result = core::str::from_utf8(&buf[..len])
- .expect("[validity] fmt::Display writes valid UTF-8 byte sequence");
- Ok(result)
-}
-
-/// Writer that fails (not panics) on OOM.
-#[cfg(feature = "alloc")]
-struct StringWriter<'a> {
- /// Destination buffer.
- buffer: &'a mut String,
- /// Memory allocation error.
- error: Option<TryReserveError>,
-}
-
-#[cfg(feature = "alloc")]
-impl fmt::Write for StringWriter<'_> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- if self.error.is_some() {
- return Err(fmt::Error);
- }
- if let Err(e) = self.buffer.try_reserve(s.len()) {
- self.error = Some(e);
- return Err(fmt::Error);
- }
- // This should never fail since `.try_reserve(s.len())` succeeded.
- self.buffer.push_str(s);
- Ok(())
- }
-}
-
-/// Appends the data to the string.
-///
-/// When allocation failure happens, incompletely appended strings won't be
-/// stripped. Callers are responsible to clean up the destination if necessary.
-#[cfg(feature = "alloc")]
-pub fn try_append_to_string<T: fmt::Display>(
- dest: &mut String,
- value: &T,
-) -> Result<(), TryReserveError> {
- let mut writer = StringWriter {
- buffer: dest,
- error: None,
- };
- if write!(writer, "{}", value).is_err() {
- let e = writer
- .error
- .expect("[consistency] allocation error should be set on formatting failure");
- return Err(e);
- }
- Ok(())
-}
-
-/// Returns true if the two equals after they are converted to strings.
-pub(crate) fn eq_str_display<T>(s: &str, d: &T) -> bool
-where
- T: ?Sized + fmt::Display,
-{
- /// Dummy writer to compare the formatted object to the given string.
- struct CmpWriter<'a>(&'a str);
- impl fmt::Write for CmpWriter<'_> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- if self.0.len() < s.len() {
- return Err(fmt::Error);
- }
- let (prefix, rest) = self.0.split_at(s.len());
- self.0 = rest;
- if prefix == s {
- Ok(())
- } else {
- Err(fmt::Error)
- }
- }
- }
-
- let mut writer = CmpWriter(s);
- let succeeded = write!(writer, "{}", d).is_ok();
- succeeded && writer.0.is_empty()
-}
-
-/// A debug-printable type to hide the sensitive information.
-#[derive(Clone, Copy)]
-pub(crate) struct Censored;
-
-impl core::fmt::Debug for Censored {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
- f.write_str("{censored}")
- }
-}
-
-/// [`ToString`][`alloc::string::ToString`], but without panic.
-#[cfg(feature = "alloc")]
-pub trait ToStringFallible: alloc::string::ToString {
- /// [`ToString::to_string`][`alloc::string::ToString::to_string`], but without panic on OOM.
- fn try_to_string(&self) -> Result<String, TryReserveError>;
-}
-
-#[cfg(feature = "alloc")]
-impl<T: fmt::Display> ToStringFallible for T {
- /// [`ToString::to_string`][`alloc::string::ToString::to_string`], but without panic on OOM.
- #[inline]
- fn try_to_string(&self) -> Result<String, TryReserveError> {
- let mut buf = String::new();
- try_append_to_string(&mut buf, self)?;
- Ok(buf)
- }
-}
-
-/// A trait for types that can be converted to a dedicated allocated string types.
-#[cfg(feature = "alloc")]
-pub trait ToDedicatedString {
- /// Conversion target type.
- type Target;
-
- /// Converts the value to the allocated string.
- fn try_to_dedicated_string(&self) -> Result<Self::Target, TryReserveError>;
-
- /// Converts the value to the allocated string.
- ///
- /// # Panics
- ///
- /// Panics if memory allocation error occured.
- #[inline]
- #[must_use]
- fn to_dedicated_string(&self) -> Self::Target {
- self.try_to_dedicated_string()
- .expect("failed to allocate enough memory")
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn eq_str_display_1() {
- assert!(eq_str_display("hello", "hello"));
- assert!(eq_str_display("42", &42));
-
- assert!(eq_str_display(
- r#"\x00\t\r\n\xff\\"#,
- &b"\x00\t\r\n\xff\\".escape_ascii()
- ));
-
- assert!(!eq_str_display("hello", "world"));
- assert!(!eq_str_display("hello world", "hello"));
- assert!(!eq_str_display("hello", "hello world"));
- assert!(!eq_str_display("42", &4));
- assert!(!eq_str_display("4", &42));
- }
-}
diff --git a/vendor/iri-string/src/lib.rs b/vendor/iri-string/src/lib.rs
deleted file mode 100644
index 9be41a9b..00000000
--- a/vendor/iri-string/src/lib.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-//! String types for [RFC 3987 Internationalized Resource Identifiers (IRIs)][RFC 3987] and
-//! [RFC 3986 Uniform Resource Identifiers (URIs)][RFC 3986].
-//!
-//! Note that this crate does not have any extra knowledge about protocols.
-//! Comparisons between IRI strings by `PartialEq` and `Eq` is implemented as [simple string
-//! comparison](https://tools.ietf.org/html/rfc3986#section-6.2.1).
-//! You should implement by yourself or use another crate to use such extra knowledge to compare
-//! IRIs / URIs.
-//!
-//! # Capability
-//!
-//! This crate provides many features for IRIs / URIs.
-//!
-//! ## String types
-//!
-//! [`types` module][`types`] module provides various string types for IRIs and URIs.
-//! The borrowed string types are unsized slice types (such as `[u8]` and `str`)
-//! and not a sized struct, so they are highly interoperable with for example
-//! `Cow` and `Rc`. Conversions between `&str` and borrwed IRI string types are easy.
-//!
-//! ## Resolvers
-//!
-//! [`resolve` module][`resolve`] provides IRI / URI references resolver.
-//! However, you are recommended to use methods of string types such as
-//! [`RiReferenceStr::resolve_against()`] or [`RiRelativeStr::resolve_against()`]
-//! if you don't intend to resolve multiple IRIs against the same base.
-//!
-//! ## Validators
-//!
-//! Validator functions are provided from [`validate` module][`validate`].
-//!
-//! ## Percent encoding
-//!
-//! [`percent_encode` module][`percent_encode`] provides a converter to encode
-//! user-provided string into percent-encoded one (if syntax requires so).
-//!
-//! ## IRI builder
-//!
-//! [`build` module][`build`] provides IRI builder.
-//!
-//! ## URI template (RFC 6570)
-//!
-//! [`template` module][`template`] provides an RFC 6570 URI Template processor.
-//!
-//! # Feature flags
-//!
-//! ## `std` and `alloc` support
-//!
-//! This crate supports `no_std` usage.
-//!
-//! * `alloc` feature:
-//! + Std library or `alloc` crate is required.
-//! + This feature enables types and functions which require memory allocation,
-//! e.g. `types::IriString` and `types::IriRelativeStr::resolve_against()`.
-//! * `std` feature (**enabled by default**):
-//! + Std library is required.
-//! + This automatically enables `alloc` feature.
-//! + The feature let the crate utilize std-specific stuff, such as `std::error::Error` trait.
-//! * With neither of them:
-//! + The crate can be used in `no_std` environment.
-//!
-//! ## Other features
-//!
-//! * `serde`
-//! + Enables serde support.
-//! + Implement `Serailize` and `Deserialize` traits for IRI / URI types.
-//! * `memchr`
-//! + Enables faster internal character search.
-//!
-//! # Rationale
-//!
-//! ## `foo:`, `foo:/`, `foo://`, `foo:///`, `foo:////`, ... are valid IRIs
-//!
-//! All of these are valid IRIs.
-//! (On the other hand, all of them are invalid as relative IRI reference, because they don't
-//! match `relative-part` rule, especially `path-noscheme`, as the first path component of the
-//! relative path contains a colon.)
-//!
-//! * `foo:`
-//! + Decomposed to `<scheme="foo">:<path-empty="">`.
-//! * `foo:/`
-//! + Decomposed to `<scheme="foo">:<path-absolute="/">`.
-//! * `foo://`
-//! + Decomposed to `<scheme="foo">://<authority=""><path-absolute="">`.
-//! * `foo:///`
-//! + Decomposed to `<scheme="foo">://<authority=""><path-absolute="/">`.
-//! * `foo:////`
-//! + Decomposed to `<scheme="foo">://<authority=""><path-absolute="//">`.
-//! * `foo://///`
-//! + Decomposed to `<scheme="foo">://<authority=""><path-absolute="///">`.
-//!
-//! RFC 3986 says that "if authority is absent, path cannot start with `//`".
-//!
-//! > When authority is present, the path must either be empty or begin with a slash ("/")
-//! > character. When authority is not present, the path cannot begin with two slash characters
-//! > ("//").
-//! >
-//! > --- [RFC 3986, section 3. Syntax Components](https://tools.ietf.org/html/rfc3986#section-3).
-//!
-//! > If a URI contains an authority component, then the path component must either be empty or
-//! > begin with a slash ("/") character. If a URI does not contain an authority component, then the
-//! > path cannot begin with two slash characters ("//").
-//! >
-//! > --- [RFC 3986, section 3.3. Path](https://tools.ietf.org/html/rfc3986#section-3.3)
-//!
-//! We should interpret them as "if `authority` rule is completely unused (i.e. does not match any
-//! strings **including empty string**), path cannot start with `//`".
-//! In other words, we should consider this as **explaining the ABNF of `hier-part` rule**
-//! (especially why it does not use `path` rule), but **not adding extra restriction to the rule
-//! written in ABNF**.
-//!
-//! This restriction is necessary to remove ambiguity in decomposition of some strings.
-//! For example, it is natural to decompose `foo://` to `<scheme="foo">:<path="//">` or
-//! `<scheme="foo">://<authority=""><path="">`.
-//! The restriction, **which is already encoded to the ABNF rule**, tells us to always decompose to
-//! the latter form, rather than the former one.
-//!
-//! Readers of the spec might be confused by "when authority is **present**" and "if a URI
-//! **contains** an authority component, which is unclear.
-//! However, based on the interpretation above, we should consider authority part with empty string
-//! as satisfying the condition "authority is **present**".
-//!
-//! ## IRI resolution can fail
-//!
-//! For some inputs, resulting string of IRI normalization and resolution can be syntactically
-//! correct but semantically wrong. In such cases, the normalizer and resolver provided by this
-//! crate do not silently "fix" the IRI by non-standard processing, but just
-//! fail by returning `Err(_)`.
-//!
-//! For details, see the documentation of [`normalize`] module.
-//!
-//! [RFC 3986]: https://tools.ietf.org/html/rfc3986
-//! [RFC 3987]: https://tools.ietf.org/html/rfc3987
-//! [`RiReferenceStr::resolve_against()`]: `types::RiReferenceStr::resolve_against`
-//! [`RiRelativeStr::resolve_against()`]: `types::RiRelativeStr::resolve_against`
-#![warn(missing_docs)]
-#![warn(unsafe_op_in_unsafe_fn)]
-#![warn(clippy::missing_docs_in_private_items)]
-#![warn(clippy::undocumented_unsafe_blocks)]
-#![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(docsrs, feature(doc_auto_cfg))]
-
-#[cfg(feature = "alloc")]
-extern crate alloc;
-
-pub mod build;
-pub mod components;
-pub mod convert;
-pub mod format;
-pub mod mask_password;
-pub mod normalize;
-pub(crate) mod parser;
-pub mod percent_encode;
-pub(crate) mod raw;
-pub mod resolve;
-pub mod spec;
-pub mod template;
-pub mod types;
-pub mod validate;
diff --git a/vendor/iri-string/src/mask_password.rs b/vendor/iri-string/src/mask_password.rs
deleted file mode 100644
index ea3fda3b..00000000
--- a/vendor/iri-string/src/mask_password.rs
+++ /dev/null
@@ -1,298 +0,0 @@
-//! Password masker.
-
-use core::fmt::{self, Write as _};
-use core::ops::Range;
-
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::borrow::ToOwned;
-#[cfg(feature = "alloc")]
-use alloc::collections::TryReserveError;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-
-use crate::components::AuthorityComponents;
-#[cfg(feature = "alloc")]
-use crate::format::ToDedicatedString;
-use crate::spec::Spec;
-use crate::types::{RiAbsoluteStr, RiReferenceStr, RiRelativeStr, RiStr};
-#[cfg(feature = "alloc")]
-use crate::types::{RiAbsoluteString, RiReferenceString, RiRelativeString, RiString};
-
-/// Returns the range of the password to hide.
-pub(crate) fn password_range_to_hide<S: Spec>(iri: &RiReferenceStr<S>) -> Option<Range<usize>> {
- /// Spec-agnostic internal implementation of `password_range_to_hide`.
- fn inner(iri: &str, userinfo: &str) -> Option<Range<usize>> {
- // Length (including `//`) before the `authority` compontent.
- // 2: `"//".len()`.
- let authority_start = 2 + iri
- .find("//")
- .expect("[validity] `authority` component must be prefixed with `//`");
- let end = authority_start + userinfo.len();
- let start = authority_start + userinfo.find(':').map_or_else(|| userinfo.len(), |v| v + 1);
- Some(start..end)
- }
-
- let authority_components = AuthorityComponents::from_iri(iri)?;
- let userinfo = authority_components.userinfo()?;
- inner(iri.as_str(), userinfo)
-}
-
-/// Writes the URI with the password part replaced.
-fn write_with_masked_password<D>(
- f: &mut fmt::Formatter<'_>,
- s: &str,
- pw_range: Range<usize>,
- alt: &D,
-) -> fmt::Result
-where
- D: ?Sized + fmt::Display,
-{
- debug_assert!(
- s.len() >= pw_range.end,
- "[consistency] password range must be inside the IRI"
- );
-
- f.write_str(&s[..pw_range.start])?;
- alt.fmt(f)?;
- f.write_str(&s[pw_range.end..])?;
- Ok(())
-}
-
-/// Writes an IRI with the password part trimmed.
-fn write_trim_password(f: &mut fmt::Formatter<'_>, s: &str, pw_range: Range<usize>) -> fmt::Result {
- write_with_masked_password(f, s, pw_range, "")
-}
-
-/// A wrapper of an IRI string that masks the non-empty password when `Display`ed.
-///
-/// This is a retrun type of `mask_password` method of IRI string types (such as
-/// [`RiStr::mask_password`]).
-///
-/// # Examples
-///
-/// ```
-/// # use iri_string::validate::Error;
-/// # #[cfg(feature = "alloc")] {
-/// use iri_string::types::UriReferenceStr;
-///
-/// let iri = UriReferenceStr::new("http://user:password@example.com/path?query")?;
-/// let masked = iri.mask_password();
-/// assert_eq!(masked.to_string(), "http://user:@example.com/path?query");
-///
-/// assert_eq!(
-/// masked.replace_password("${password}").to_string(),
-/// "http://user:${password}@example.com/path?query"
-/// );
-/// # }
-/// # Ok::<_, Error>(())
-/// ```
-///
-/// [`RiStr::mask_password`]: `crate::types::RiStr::mask_password`
-#[derive(Clone, Copy)]
-pub struct PasswordMasked<'a, T: ?Sized> {
- /// IRI reference.
- iri_ref: &'a T,
-}
-
-impl<'a, T: ?Sized> PasswordMasked<'a, T> {
- /// Creates a new `PasswordMasked` object.
- #[inline]
- #[must_use]
- pub(crate) fn new(iri_ref: &'a T) -> Self {
- Self { iri_ref }
- }
-}
-
-/// Implements traits for `PasswordMasked`.
-macro_rules! impl_mask {
- ($borrowed:ident, $owned:ident) => {
- impl<'a, S: Spec> PasswordMasked<'a, $borrowed<S>> {
- /// Replaces the password with the given arbitrary content.
- ///
- /// Note that the result might be invalid as an IRI since arbitrary string
- /// can go to the place of the password.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("http://user:password@example.com/path?query")?;
- /// let masked = iri.mask_password();
- ///
- /// assert_eq!(
- /// masked.replace_password("${password}").to_string(),
- /// "http://user:${password}@example.com/path?query"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn replace_password<D>(&self, alt: D) -> PasswordReplaced<'a, $borrowed<S>, D>
- where
- D: fmt::Display,
- {
- PasswordReplaced::with_replacer(self.iri_ref, move |_| alt)
- }
-
- /// Replaces the password with the given arbitrary content.
- ///
- /// Note that the result might be invalid as an IRI since arbitrary string
- /// can go to the place of the password.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("http://user:password@example.com/path?query")?;
- /// let masked = iri.mask_password();
- ///
- /// let replaced = masked
- /// .replace_password_with(|password| format!("{{{} chars}}", password.len()));
- /// assert_eq!(
- /// replaced.to_string(),
- /// "http://user:{8 chars}@example.com/path?query"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn replace_password_with<F, D>(
- &self,
- replace: F,
- ) -> PasswordReplaced<'a, $borrowed<S>, D>
- where
- F: FnOnce(&str) -> D,
- D: fmt::Display,
- {
- PasswordReplaced::with_replacer(self.iri_ref, replace)
- }
- }
-
- impl<S: Spec> fmt::Display for PasswordMasked<'_, $borrowed<S>> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match password_range_to_hide(self.iri_ref.as_ref()) {
- Some(pw_range) => write_trim_password(f, self.iri_ref.as_str(), pw_range),
- None => self.iri_ref.fmt(f),
- }
- }
- }
-
- impl<S: Spec> fmt::Debug for PasswordMasked<'_, $borrowed<S>> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_char('<')?;
- fmt::Display::fmt(self, f)?;
- f.write_char('>')
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<S: Spec> ToDedicatedString for PasswordMasked<'_, $borrowed<S>> {
- type Target = $owned<S>;
-
- fn try_to_dedicated_string(&self) -> Result<Self::Target, TryReserveError> {
- let pw_range = match password_range_to_hide(self.iri_ref.as_ref()) {
- Some(pw_range) => pw_range,
- None => return Ok(self.iri_ref.to_owned()),
- };
- let mut s = String::new();
- let iri_ref = self.iri_ref.as_str();
- s.try_reserve(iri_ref.len() - (pw_range.end - pw_range.start))?;
- s.push_str(&iri_ref[..pw_range.start]);
- s.push_str(&iri_ref[pw_range.end..]);
- // SAFETY: IRI remains valid and type does not change if
- // the password is trimmed.
- let iri = unsafe { <$owned<S>>::new_maybe_unchecked(s) };
- Ok(iri)
- }
- }
- };
-}
-
-impl_mask!(RiReferenceStr, RiReferenceString);
-impl_mask!(RiStr, RiString);
-impl_mask!(RiAbsoluteStr, RiAbsoluteString);
-impl_mask!(RiRelativeStr, RiRelativeString);
-
-/// A wrapper of an IRI string that replaces the non-empty password when `Display`ed.
-///
-/// This is a retrun type of `mask_password` method of IRI string types (such as
-/// [`RiStr::mask_password`]).
-///
-/// Note that the result might be invalid as an IRI since arbitrary string can
-/// go to the place of the password.
-#[cfg_attr(
- feature = "alloc",
- doc = "Because of this, [`ToDedicatedString`] trait is not implemented for this type."
-)]
-///
-/// [`PasswordMasked::replace_password`]: `PasswordMasked::replace_password`
-pub struct PasswordReplaced<'a, T: ?Sized, D> {
- /// IRI reference.
- iri_ref: &'a T,
- /// Password range and alternative content.
- password: Option<(Range<usize>, D)>,
-}
-
-impl<'a, T, D> PasswordReplaced<'a, T, D>
-where
- T: ?Sized,
- D: fmt::Display,
-{
- /// Creates a new `PasswordMasked` object.
- ///
- /// # Precondition
- ///
- /// The given string must be a valid IRI reference.
- #[inline]
- #[must_use]
- pub(crate) fn with_replacer<S, F>(iri_ref: &'a T, replace: F) -> Self
- where
- S: Spec,
- T: AsRef<RiReferenceStr<S>>,
- F: FnOnce(&str) -> D,
- {
- let iri_ref_asref = iri_ref.as_ref();
- let password = password_range_to_hide(iri_ref_asref)
- .map(move |pw_range| (pw_range.clone(), replace(&iri_ref_asref.as_str()[pw_range])));
- Self { iri_ref, password }
- }
-}
-
-/// Implements traits for `PasswordReplaced`.
-macro_rules! impl_replace {
- ($borrowed:ident, $owned:ident) => {
- impl<S: Spec, D: fmt::Display> fmt::Display for PasswordReplaced<'_, $borrowed<S>, D> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match &self.password {
- Some((pw_range, alt)) => {
- write_with_masked_password(f, self.iri_ref.as_str(), pw_range.clone(), alt)
- }
- None => self.iri_ref.fmt(f),
- }
- }
- }
-
- impl<S: Spec, D: fmt::Display> fmt::Debug for PasswordReplaced<'_, $borrowed<S>, D> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_char('<')?;
- fmt::Display::fmt(self, f)?;
- f.write_char('>')
- }
- }
- };
-}
-
-impl_replace!(RiReferenceStr, RiReferenceString);
-impl_replace!(RiStr, RiString);
-impl_replace!(RiAbsoluteStr, RiAbsoluteString);
-impl_replace!(RiRelativeStr, RiRelativeString);
diff --git a/vendor/iri-string/src/normalize.rs b/vendor/iri-string/src/normalize.rs
deleted file mode 100644
index a00fa44a..00000000
--- a/vendor/iri-string/src/normalize.rs
+++ /dev/null
@@ -1,691 +0,0 @@
-//! Normalization.
-//!
-//! # IRI normalization (and resolution) can fail
-//!
-//! Though this is not explicitly stated in RFC 3986, IRI normalization can fail.
-//! For example, `foo:.///bar`, `foo:./..//bar`, and `foo:/..//bar` are all
-//! normalized to `foo://bar` as a string. However, IRI without authority (note
-//! that this is different from "with empty authority") cannot have a path
-//! starting with `//`, since it is ambiguous and can be interpreted as an IRI
-//! with authority. So, `foo://bar` is decomposed as scheme `foo`, authority
-//! `bar`, and empty path. The expected result is the combination of scheme
-//! `foo`, no authority, and path `//bar` (though this is not possible to
-//! serialize), so the algorithm fails as it cannot return the intended result.
-//!
-//! IRI resolution can also fail since it (conditionally) invokes normalization
-//! during the resolution process. For example, resolving a reference `.///bar`
-//! or `/..//bar` against the base `foo:` fail.
-//!
-//! Thus, IRI resolution can fail for some abnormal cases.
-//!
-//! Note that this kind of failure can happen only when the base IRI has no
-//! authority and empty path. This would be rare in the wild, since many people
-//! would use an IRI with authority part, such as `http://`.
-//!
-//! If you are handling `scheme://`-style URIs and IRIs, don't worry about the
-//! failure. Currently no cases are known to fail when at least one of the base
-//! IRI or the relative IRI contains authorities.
-//!
-//! To know what will happen on resolution failure, see the module documentation
-//! for [`resolve`][`crate::resolve`].
-//!
-//! ## Examples
-//!
-//! ### Normalization failure
-//!
-//! ```
-//! # #[cfg(feature = "alloc")] {
-//! use iri_string::normalize::Error;
-//! use iri_string::types::{IriAbsoluteStr, IriReferenceStr};
-//!
-//! let base = IriAbsoluteStr::new("foo:.///bar")?;
-//! assert!(
-//! base.normalize().ensure_rfc3986_normalizable().is_err(),
-//! "this normalization should fails without WAHTWG URL Standard serialization"
-//! );
-//! # }
-//! # Ok::<_, iri_string::validate::Error>(())
-//! ```
-//!
-//! ### Resolution failure
-//!
-//! ```
-//! # #[cfg(feature = "alloc")] {
-//! use iri_string::types::{IriAbsoluteStr, IriReferenceStr};
-//!
-//! let base = IriAbsoluteStr::new("scheme:")?;
-//! {
-//! let reference = IriReferenceStr::new(".///bar")?;
-//! let result = reference.resolve_against(base)
-//! .ensure_rfc3986_normalizable();
-//! assert!(result.is_err());
-//! }
-//!
-//! {
-//! let reference2 = IriReferenceStr::new("/..//bar")?;
-//! // Resulting string will be `scheme://bar`, but `bar` should be a path
-//! // segment, not a host. So, the semantically correct target IRI cannot
-//! // be represented.
-//! let result2 = reference2.resolve_against(base)
-//! .ensure_rfc3986_normalizable();
-//! assert!(result2.is_err());
-//! }
-//! # }
-//! # Ok::<_, iri_string::validate::Error>(())
-//! ```
-
-mod error;
-mod path;
-mod pct_case;
-
-use core::fmt::{self, Display as _, Write as _};
-use core::marker::PhantomData;
-
-#[cfg(feature = "alloc")]
-use alloc::collections::TryReserveError;
-
-use crate::components::{RiReferenceComponents, Splitter};
-#[cfg(feature = "alloc")]
-use crate::format::{ToDedicatedString, ToStringFallible};
-use crate::parser::str::rfind_split_hole;
-use crate::parser::trusted::is_ascii_only_host;
-use crate::spec::Spec;
-use crate::types::{RiAbsoluteStr, RiReferenceStr, RiStr};
-#[cfg(feature = "alloc")]
-use crate::types::{RiAbsoluteString, RiString};
-
-pub use self::error::Error;
-pub(crate) use self::path::{Path, PathCharacteristic, PathToNormalize};
-pub(crate) use self::pct_case::{
- is_pct_case_normalized, NormalizedAsciiOnlyHost, PctCaseNormalized,
-};
-
-/// Normalization algorithm.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum NormalizationMode {
- /// No normalization.
- None,
- /// Default normalization mode.
- ///
- /// Applies RFC 3986 normalization whenever possible. When not possible,
- /// applies serialization algorithm defined in WHATWG URL standard.
- Default,
- /// WHATWG-like normalization mode.
- ///
- /// Preserves relative path as is (modulo case/pct normalization) when the
- /// authority component is absent.
- PreserveAuthoritylessRelativePath,
-}
-
-impl NormalizationMode {
- /// Returns true if case normalization and percent-encoding normalization should be applied.
- ///
- /// Note that even when this option is `true`, plain US-ASCII characters
- /// won't be automatically lowered. Users should apply case normalization
- /// for US-ASCII only `host` component by themselves.
- #[inline]
- #[must_use]
- fn case_pct_normalization(self) -> bool {
- match self {
- Self::None => false,
- Self::Default | Self::PreserveAuthoritylessRelativePath => true,
- }
- }
-}
-
-/// Normalizedness check algorithm.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum NormalizednessCheckMode {
- /// Default algorithm (corresponding to [`NormalizationMode::Default`]).
- Default,
- /// Strict RFC 3986 normalization.
- Rfc3986,
- /// WHATWG-like normalization algorithm (corresponding to
- /// [`NormalizationMode::PreserveAuthoritylessRelativePath`]).
- PreserveAuthoritylessRelativePath,
-}
-
-/// Normalization operation.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) struct NormalizationOp {
- /// Normalization mode.
- pub(crate) mode: NormalizationMode,
-}
-
-/// Spec-agnostic IRI normalization/resolution input.
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct NormalizationInput<'a> {
- /// Target scheme.
- scheme: &'a str,
- /// Target authority.
- authority: Option<&'a str>,
- /// Target path without dot-removal.
- path: Path<'a>,
- /// Target query.
- query: Option<&'a str>,
- /// Target fragment.
- fragment: Option<&'a str>,
- /// Normalization type.
- op: NormalizationOp,
-}
-
-impl<'a> NormalizationInput<'a> {
- /// Creates a `NormalizedInput` from IRIs to resolve.
- #[inline]
- #[must_use]
- pub(crate) fn with_resolution_params<S: Spec>(
- base_components: &RiReferenceComponents<'a, S>,
- reference: &'a RiReferenceStr<S>,
- ) -> Self {
- let r = RiReferenceComponents::from(reference);
-
- Self::create_normalization_input(
- r.iri.as_str(),
- &r.splitter,
- base_components.iri.as_str(),
- &base_components.splitter,
- )
- }
-
- /// Creates a `NormalizationInput` from components to resolve an IRI.
- #[must_use]
- fn create_normalization_input(
- r_iri: &'a str,
- r: &Splitter,
- b_iri: &'a str,
- b: &Splitter,
- ) -> Self {
- /// The toplevel component the reference has.
- #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
- enum RefToplevel {
- /// Scheme.
- Scheme,
- /// Authority.
- Authority,
- /// Path.
- Path,
- /// Query.
- Query,
- /// Reference is empty or has only fragment.
- None,
- }
-
- impl RefToplevel {
- /// Choose a component from either of the reference or the base,
- /// based on the toplevel component of the reference.
- #[inline]
- #[must_use]
- fn choose_then<T, F, G>(self, component: RefToplevel, reference: F, base: G) -> T
- where
- F: FnOnce() -> T,
- G: FnOnce() -> T,
- {
- if self <= component {
- reference()
- } else {
- base()
- }
- }
- }
-
- let ref_toplevel = if r.has_scheme() {
- RefToplevel::Scheme
- } else if r.has_authority() {
- RefToplevel::Authority
- } else if !r.is_path_empty(r_iri.len()) {
- RefToplevel::Path
- } else if r.has_query() {
- RefToplevel::Query
- } else {
- RefToplevel::None
- };
-
- let path = match ref_toplevel {
- RefToplevel::Scheme | RefToplevel::Authority => {
- Path::NeedsProcessing(PathToNormalize::from_single_path(r.path_str(r_iri)))
- }
- RefToplevel::Path => {
- let r_path = r.path_str(r_iri);
- if r_path.starts_with('/') {
- Path::NeedsProcessing(PathToNormalize::from_single_path(r_path))
- } else {
- // About this branch, see
- // <https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.3>.
- //
- // > o If the base URI has a defined authority component and an empty
- // > path, then return a string consisting of "/" concatenated with the
- // > reference's path; otherwise,
- let b_path = b.path_str(b_iri);
- let b_path = if b.has_authority() && b_path.is_empty() {
- "/"
- } else {
- b_path
- };
- Path::NeedsProcessing(PathToNormalize::from_paths_to_be_resolved(
- b_path, r_path,
- ))
- }
- }
- RefToplevel::Query | RefToplevel::None => Path::Done(b.path_str(b_iri)),
- };
-
- Self {
- scheme: r.scheme_str(r_iri).unwrap_or_else(|| {
- b.scheme_str(b_iri)
- .expect("[validity] non-relative IRI must have a scheme")
- }),
- authority: ref_toplevel.choose_then(
- RefToplevel::Authority,
- || r.authority_str(r_iri),
- || b.authority_str(b_iri),
- ),
- path,
- query: ref_toplevel.choose_then(
- RefToplevel::Query,
- || r.query_str(r_iri),
- || b.query_str(b_iri),
- ),
- fragment: r.fragment_str(r_iri),
- op: NormalizationOp {
- mode: NormalizationMode::None,
- },
- }
- }
-}
-
-impl<'a, S: Spec> From<&'a RiStr<S>> for NormalizationInput<'a> {
- fn from(iri: &'a RiStr<S>) -> Self {
- let components = RiReferenceComponents::<S>::from(iri.as_ref());
- let (scheme, authority, path, query, fragment) = components.to_major();
- let scheme = scheme.expect("[validity] `absolute IRI must have `scheme`");
- let path = Path::NeedsProcessing(PathToNormalize::from_single_path(path));
-
- NormalizationInput {
- scheme,
- authority,
- path,
- query,
- fragment,
- op: NormalizationOp {
- mode: NormalizationMode::None,
- },
- }
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<'a, S: Spec> From<&'a RiString<S>> for NormalizationInput<'a> {
- #[inline]
- fn from(iri: &'a RiString<S>) -> Self {
- Self::from(iri.as_slice())
- }
-}
-
-impl<'a, S: Spec> From<&'a RiAbsoluteStr<S>> for NormalizationInput<'a> {
- fn from(iri: &'a RiAbsoluteStr<S>) -> Self {
- let components = RiReferenceComponents::<S>::from(iri.as_ref());
- let (scheme, authority, path, query, fragment) = components.to_major();
- let scheme = scheme.expect("[validity] `absolute IRI must have `scheme`");
- let path = Path::NeedsProcessing(PathToNormalize::from_single_path(path));
-
- NormalizationInput {
- scheme,
- authority,
- path,
- query,
- fragment,
- op: NormalizationOp {
- mode: NormalizationMode::None,
- },
- }
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<'a, S: Spec> From<&'a RiAbsoluteString<S>> for NormalizationInput<'a> {
- #[inline]
- fn from(iri: &'a RiAbsoluteString<S>) -> Self {
- Self::from(iri.as_slice())
- }
-}
-
-impl NormalizationInput<'_> {
- /// Checks if the path is normalizable by RFC 3986 algorithm.
- ///
- /// Returns `Ok(())` when normalizable, returns `Err(_)` if not.
- pub(crate) fn ensure_rfc3986_normalizable(&self) -> Result<(), Error> {
- if self.authority.is_some() {
- return Ok(());
- }
- match self.path {
- Path::Done(_) => Ok(()),
- Path::NeedsProcessing(path) => path.ensure_rfc3986_normalizable_with_authority_absent(),
- }
- }
-}
-
-/// Writable as a normalized IRI.
-///
-/// Note that this implicitly apply serialization rule defined by WHATWG URL
-/// Standard (to handle normalization impossible by RFC 3986) because `Display`
-/// should not fail by reasons other than backend I/O failure. If you make the
-/// normalization fail in such cases, check if the path starts with `/./`.
-/// When the normalization succeeds by RFC 3986 algorithm, the path never starts
-/// with `/./`.
-struct NormalizedInner<'a, S> {
- /// Spec-agnostic normalization input.
- input: NormalizationInput<'a>,
- /// Spec.
- _spec: PhantomData<fn() -> S>,
-}
-
-impl<S: Spec> fmt::Debug for NormalizedInner<'_, S> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Normalized")
- .field("input", &self.input)
- .finish()
- }
-}
-
-impl<'a, S: Spec> NormalizedInner<'a, S> {
- /// Creates a new `Normalized` object from the given input.
- #[inline]
- #[must_use]
- fn from_input(input: NormalizationInput<'a>) -> Self {
- Self {
- input,
- _spec: PhantomData,
- }
- }
-}
-
-impl<S: Spec> fmt::Display for NormalizedInner<'_, S> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // Write the scheme.
- if self.input.op.mode.case_pct_normalization() {
- normalize_scheme(f, self.input.scheme)?;
- } else {
- f.write_str(self.input.scheme)?;
- }
- f.write_str(":")?;
-
- // Write the authority if available.
- if let Some(authority) = self.input.authority {
- f.write_str("//")?;
- if self.input.op.mode.case_pct_normalization() {
- normalize_authority::<S>(f, authority)?;
- } else {
- // No case/pct normalization.
- f.write_str(authority)?;
- }
- }
-
- // Process and write the path.
- match self.input.path {
- Path::Done(s) => {
- if self.input.op.mode.case_pct_normalization() {
- // Normalize the path.
- PathToNormalize::from_single_path(s).fmt_write_normalize::<S, _>(
- f,
- self.input.op,
- self.input.authority.is_some(),
- )?
- } else {
- // No normalization.
- f.write_str(s)?
- }
- }
- Path::NeedsProcessing(path) => {
- path.fmt_write_normalize::<S, _>(f, self.input.op, self.input.authority.is_some())?
- }
- }
-
- // Write the query if available.
- if let Some(query) = self.input.query {
- f.write_char('?')?;
- if self.input.op.mode.case_pct_normalization() {
- normalize_query::<S>(f, query)?;
- } else {
- f.write_str(query)?;
- }
- }
-
- // Write the fragment if available.
- if let Some(fragment) = self.input.fragment {
- f.write_char('#')?;
- if self.input.op.mode.case_pct_normalization() {
- normalize_fragment::<S>(f, fragment)?;
- } else {
- f.write_str(fragment)?;
- }
- }
-
- Ok(())
- }
-}
-
-/// Writes the normalized scheme.
-pub(crate) fn normalize_scheme(f: &mut fmt::Formatter<'_>, scheme: &str) -> fmt::Result {
- // Apply case normalization.
- //
- // > namely, that the scheme and US-ASCII only host are case
- // > insensitive and therefore should be normalized to lowercase.
- // >
- // > --- <https://datatracker.ietf.org/doc/html/rfc3987#section-5.3.2.1>.
- //
- // Note that `scheme` consists of only ASCII characters and contains
- // no percent-encoded characters.
- scheme
- .chars()
- .map(|c| c.to_ascii_lowercase())
- .try_for_each(|c| f.write_char(c))
-}
-
-/// Writes the normalized authority.
-fn normalize_authority<S: Spec>(f: &mut fmt::Formatter<'_>, authority: &str) -> fmt::Result {
- let host_port = match rfind_split_hole(authority, b'@') {
- Some((userinfo, host_port)) => {
- // Don't lowercase `userinfo` even if it is ASCII only. `userinfo`
- // is not a part of `host`.
- PctCaseNormalized::<S>::new(userinfo).fmt(f)?;
- f.write_char('@')?;
- host_port
- }
- None => authority,
- };
- normalize_host_port::<S>(f, host_port)
-}
-
-/// Writes the normalized host and port.
-pub(crate) fn normalize_host_port<S: Spec>(
- f: &mut fmt::Formatter<'_>,
- host_port: &str,
-) -> fmt::Result {
- // If the suffix is a colon, it is a delimiter between the host and empty
- // port. An empty port should be removed during normalization (see RFC 3986
- // section 3.2.3), so strip it.
- //
- // > URI producers and normalizers should omit the port component and its
- // > ":" delimiter if port is empty or if its value would be the same as
- // > that of the scheme's default.
- // >
- // > --- [RFC 3986 section 3.2.3. Port](https://www.rfc-editor.org/rfc/rfc3986.html#section-3.2.3)
- let host_port = host_port.strip_suffix(':').unwrap_or(host_port);
-
- // Apply case normalization and percent-encoding normalization to `host`.
- // Optional `":" port` part only consists of an ASCII colon and ASCII
- // digits, so this won't affect to the test result.
- if is_ascii_only_host(host_port) {
- // If the host is ASCII characters only, make plain alphabets lower case.
- NormalizedAsciiOnlyHost::new(host_port).fmt(f)
- } else {
- PctCaseNormalized::<S>::new(host_port).fmt(f)
- }
-}
-
-/// Writes the normalized query without the '?' prefix.
-pub(crate) fn normalize_query<S: Spec>(f: &mut fmt::Formatter<'_>, query: &str) -> fmt::Result {
- // Apply percent-encoding normalization.
- PctCaseNormalized::<S>::new(query).fmt(f)
-}
-
-/// Writes the normalized query without the '#' prefix.
-pub(crate) fn normalize_fragment<S: Spec>(
- f: &mut fmt::Formatter<'_>,
- fragment: &str,
-) -> fmt::Result {
- // Apply percent-encoding normalization.
- PctCaseNormalized::<S>::new(fragment).fmt(f)
-}
-
-/// Normalized OR resolved IRI.
-///
-/// Resolved IRI can be represented by this type. In that case, the result might
-/// not be normalized. If you want the IRI resolution result to be normalized,
-/// use [`enable_normalization`][`Self::enable_normalization`] method.
-///
-/// [`Display`]: `core::fmt::Display`
-pub struct Normalized<'a, T: ?Sized> {
- /// Spec-agnostic normalization input.
- input: NormalizationInput<'a>,
- /// Expected result type.
- _ty_str: PhantomData<fn() -> T>,
-}
-
-impl<T: ?Sized> fmt::Debug for Normalized<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Normalized")
- .field("input", &self.input)
- .finish()
- }
-}
-
-impl<'a, T: ?Sized> Normalized<'a, T> {
- /// Creates a new `Normalized` object from the given input.
- #[inline]
- #[must_use]
- pub(crate) fn from_input(input: NormalizationInput<'a>) -> Self {
- Self {
- input,
- _ty_str: PhantomData,
- }
- }
-
- /// Enables the normalization.
- ///
- /// This lets the normalizer apply the case normalization, percent-encoding
- /// normalization, and dot segments removal.
- #[inline]
- pub fn enable_normalization(&mut self) {
- self.input.op.mode = NormalizationMode::Default;
- }
-
- /// Enables the normalization that preserve relative path under some condition.
- ///
- /// Note that this normalization algorithm is not compatible with RFC 3986
- /// algorithm for some inputs.
- ///
- /// See [`RiStr::normalize_but_preserve_authorityless_relative_path()`]
- /// for detail.
- #[inline]
- pub fn enable_normalization_preserving_authorityless_relative_path(&mut self) {
- self.input.op.mode = NormalizationMode::PreserveAuthoritylessRelativePath;
- }
-
- /// Returns `Self` with normalization enabled.
- #[inline]
- #[must_use]
- pub fn and_normalize(mut self) -> Self {
- self.enable_normalization();
- self
- }
-
- /// Returns `Self` with special normalization enabled.
- ///
- /// Note that this normalization algorithm is not compatible with RFC 3986
- /// algorithm for some inputs.
- ///
- /// See [`RiStr::normalize_but_preserve_authorityless_relative_path()`]
- /// for detail.
- #[inline]
- #[must_use]
- pub fn and_normalize_but_preserve_authorityless_relative_path(mut self) -> Self {
- self.enable_normalization_preserving_authorityless_relative_path();
- self
- }
-
- /// Checks if the path is normalizable by RFC 3986 algorithm.
- ///
- /// Returns `Ok(())` when normalizable, returns `Err(_)` if not.
- #[inline]
- pub fn ensure_rfc3986_normalizable(&self) -> Result<(), Error> {
- self.input.ensure_rfc3986_normalizable()
- }
-}
-
-impl<S: Spec> fmt::Display for Normalized<'_, RiStr<S>> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- NormalizedInner::<S>::from_input(self.input).fmt(f)
- }
-}
-
-impl<S: Spec> fmt::Display for Normalized<'_, RiAbsoluteStr<S>> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- NormalizedInner::<S>::from_input(self.input).fmt(f)
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> ToDedicatedString for Normalized<'_, RiStr<S>> {
- type Target = RiString<S>;
-
- fn try_to_dedicated_string(&self) -> Result<Self::Target, TryReserveError> {
- let s = self.try_to_string()?;
- Ok(TryFrom::try_from(s).expect("[validity] the normalization result must be a valid IRI"))
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> From<Normalized<'_, RiStr<S>>> for RiString<S> {
- #[inline]
- fn from(v: Normalized<'_, RiStr<S>>) -> Self {
- v.to_dedicated_string()
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> From<&Normalized<'_, RiStr<S>>> for RiString<S> {
- #[inline]
- fn from(v: &Normalized<'_, RiStr<S>>) -> Self {
- v.to_dedicated_string()
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> ToDedicatedString for Normalized<'_, RiAbsoluteStr<S>> {
- type Target = RiAbsoluteString<S>;
-
- fn try_to_dedicated_string(&self) -> Result<Self::Target, TryReserveError> {
- let s = self.try_to_string()?;
- Ok(TryFrom::try_from(s).expect("[validity] the normalization result must be a valid IRI"))
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> From<Normalized<'_, RiAbsoluteStr<S>>> for RiAbsoluteString<S> {
- #[inline]
- fn from(v: Normalized<'_, RiAbsoluteStr<S>>) -> Self {
- v.to_dedicated_string()
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> From<&Normalized<'_, RiAbsoluteStr<S>>> for RiAbsoluteString<S> {
- #[inline]
- fn from(v: &Normalized<'_, RiAbsoluteStr<S>>) -> Self {
- v.to_dedicated_string()
- }
-}
diff --git a/vendor/iri-string/src/normalize/error.rs b/vendor/iri-string/src/normalize/error.rs
deleted file mode 100644
index a5c5c895..00000000
--- a/vendor/iri-string/src/normalize/error.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//! Normalization and resolution error.
-
-use core::fmt;
-
-/// IRI normalization and resolution error.
-///
-/// For detail about resolution failure, see [the module documentation][`crate::resolve`].
-#[derive(Debug, Clone)]
-pub struct Error(());
-
-impl Error {
- /// Creates a new error.
- pub(crate) fn new() -> Self {
- Self(())
- }
-}
-
-impl fmt::Display for Error {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("unresolvable IRI")
- }
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for Error {}
diff --git a/vendor/iri-string/src/normalize/path.rs b/vendor/iri-string/src/normalize/path.rs
deleted file mode 100644
index 4f3e3397..00000000
--- a/vendor/iri-string/src/normalize/path.rs
+++ /dev/null
@@ -1,620 +0,0 @@
-//! Path normalization.
-
-use core::fmt;
-use core::ops::Range;
-
-use crate::parser::str::{find_split_hole, rfind};
-use crate::spec::{Spec, UriSpec};
-
-use super::pct_case::PctCaseNormalized;
-use super::{Error, NormalizationMode, NormalizationOp};
-
-/// Path that is (possibly) not yet processed or being processed.
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum Path<'a> {
- /// The result. No more processing is needed.
- Done(&'a str),
- /// Not yet completely processed path.
- NeedsProcessing(PathToNormalize<'a>),
-}
-
-/// Path that needs merge and/or dot segment removal.
-///
-/// # Invariants
-///
-/// If the first field (prefix field) is not `None`, it must end with a slash.
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct PathToNormalize<'a>(Option<&'a str>, &'a str);
-
-impl<'a> PathToNormalize<'a> {
- /// Creates a `PathToNormalize` from the given single path.
- #[inline]
- #[must_use]
- pub(crate) fn from_single_path(path: &'a str) -> Self {
- Self(None, path)
- }
-
- /// Creates a `PathToNormalize` from the given base and reference paths to be resolved.
- #[must_use]
- pub(crate) fn from_paths_to_be_resolved(base: &'a str, reference: &'a str) -> Self {
- if reference.starts_with('/') {
- return Self(None, reference);
- }
-
- match rfind(base.as_bytes(), b'/') {
- Some(last_slash_pos) => Self(Some(&base[..=last_slash_pos]), reference),
- None => Self(None, reference),
- }
- }
-
- /// Returns true if the path is empty string.
- #[inline]
- #[must_use]
- fn is_empty(&self) -> bool {
- // If `self.0` is `Some(_)`, it ends with a slash, i.e. it is not empty.
- self.0.is_none() && self.1.is_empty()
- }
-
- /// Returns the length of the not yet normalized path.
- #[inline]
- #[must_use]
- pub(super) fn len(&self) -> usize {
- self.len_prefix() + self.1.len()
- }
-
- /// Returns the length of the prefix part.
- ///
- /// Returns 0 if the prefix part is empty.
- #[inline]
- #[must_use]
- fn len_prefix(&self) -> usize {
- self.0.map_or(0, |s| s.len())
- }
-
- /// Returns a byte at the given position.
- #[must_use]
- fn byte_at(&self, mut i: usize) -> Option<u8> {
- if let Some(prefix) = self.0 {
- if i < prefix.len() {
- return Some(prefix.as_bytes()[i]);
- }
- i -= prefix.len();
- }
- self.1.as_bytes().get(i).copied()
- }
-
- /// Returns the position of the next slash of the byte at the given position.
- #[must_use]
- fn find_next_slash(&self, scan_start: usize) -> Option<usize> {
- if let Some(prefix) = self.0 {
- let prefix_len = prefix.len();
- if scan_start < prefix_len {
- prefix[scan_start..].find('/').map(|rel| rel + scan_start)
- } else {
- let local_i = scan_start - prefix_len;
- self.1[local_i..].find('/').map(|rel| rel + scan_start)
- }
- } else {
- self.1[scan_start..].find('/').map(|rel| rel + scan_start)
- }
- }
-
- /// Removes the `len` characters from the beginning of `self`.
- fn remove_start(&mut self, len: usize) {
- if let Some(prefix) = self.0 {
- if let Some(suffix_trim_len) = len.checked_sub(prefix.len()) {
- self.0 = None;
- self.1 = &self.1[suffix_trim_len..];
- } else {
- self.0 = Some(&prefix[len..]);
- }
- } else {
- self.1 = &self.1[len..];
- }
- }
-
- /// Removes the prefix that are ignorable on normalization.
- // Skips the prefix dot segments without leading slashes (such as `./`,
- // `../`, and `../.././`).
- // This is necessary because such segments should be removed with the
- // FOLLOWING slashes, not leading slashes.
- fn remove_ignorable_prefix(&mut self) {
- while let Some(seg) = PathSegmentsIter::new(self).next() {
- if seg.has_leading_slash {
- // The first segment starting with a slash is not target.
- break;
- }
- match seg.kind(self) {
- SegmentKind::Dot | SegmentKind::DotDot => {
- // Attempt to skip the following slash by `+ 1`.
- let skip = self.len().min(seg.range.end + 1);
- self.remove_start(skip);
- }
- SegmentKind::Normal => break,
- }
- }
- }
-}
-
-impl PathToNormalize<'_> {
- /// Writes the normalized path.
- pub(crate) fn fmt_write_normalize<S: Spec, W: fmt::Write>(
- &self,
- f: &mut W,
- op: NormalizationOp,
- authority_is_present: bool,
- ) -> fmt::Result {
- debug_assert!(
- self.0.map_or(true, |s| s.ends_with('/')),
- "[validity] the prefix field of `PathToNormalize` should end with a slash"
- );
-
- if self.is_empty() {
- return Ok(());
- }
-
- if (op.mode == NormalizationMode::PreserveAuthoritylessRelativePath)
- && !authority_is_present
- && self.byte_at(0) != Some(b'/')
- {
- // Treat the path as "opaque", i.e. do not apply dot segments removal.
- // See <https://github.com/lo48576/iri-string/issues/29>.
- debug_assert!(
- op.mode.case_pct_normalization(),
- "[consistency] case/pct normalization should still be applied"
- );
- if let Some(prefix) = self.0 {
- write!(f, "{}", PctCaseNormalized::<S>::new(prefix))?;
- }
- write!(f, "{}", PctCaseNormalized::<S>::new(self.1))?;
- return Ok(());
- }
-
- let mut rest = *self;
-
- // Skip the prefix dot segments without leading slashes (such as `./`,
- // `../`, and `../.././`).
- // This is necessary because such segments should be removed with the
- // FOLLOWING slashes, not leading slashes.
- rest.remove_ignorable_prefix();
- if rest.is_empty() {
- // Path consists of only `/.`s and `/..`s.
- // In this case, if the authority component is present, the result
- // should be `/`, not empty.
- if authority_is_present {
- f.write_char('/')?;
- }
- return Ok(());
- }
-
- // None: No segments are written yet.
- // Some(false): Something other than `/` is already written as the path.
- // Some(true): Only a `/` is written as the path.
- let mut only_a_slash_is_written = None;
- let mut too_deep_area_may_have_dot_segments = true;
- while !rest.is_empty() && too_deep_area_may_have_dot_segments {
- /// The size of the queue to track the path segments.
- ///
- /// This should be nonzero.
- const QUEUE_SIZE: usize = 8;
-
- {
- // Skip `/.` and `/..` segments at the head.
- let mut skipped_len = 0;
- for seg in PathSegmentsIter::new(&rest) {
- match seg.kind(&rest) {
- SegmentKind::Dot | SegmentKind::DotDot => {
- debug_assert!(
- seg.has_leading_slash,
- "[consistency] `.` or `..` segments without a
- leading slash have already been skipped"
- );
- skipped_len = seg.range.end;
- }
- _ => break,
- }
- }
- rest.remove_start(skipped_len);
- if rest.is_empty() {
- // Finished with a dot segment.
- // The last `/.` or `/..` should be replaced to `/`.
- if !authority_is_present && (only_a_slash_is_written == Some(true)) {
- // Insert a dot segment to break the prefix `//`.
- // Without this, the path starts with `//` and it may
- // be confused with the prefix of an authority.
- f.write_str(".//")?;
- } else {
- f.write_char('/')?;
- }
- break;
- }
- }
-
- let mut queue: [Option<&'_ str>; QUEUE_SIZE] = Default::default();
- let mut level: usize = 0;
- let mut first_segment_has_leading_slash = false;
-
- // Find higher path segments.
- let mut end = 0;
- for seg in PathSegmentsIter::new(&rest) {
- let kind = seg.kind(&rest);
- match kind {
- SegmentKind::Dot => {
- too_deep_area_may_have_dot_segments = true;
- }
- SegmentKind::DotDot => {
- level = level.saturating_sub(1);
- too_deep_area_may_have_dot_segments = true;
- if level < queue.len() {
- queue[level] = None;
- }
- }
- SegmentKind::Normal => {
- if level < queue.len() {
- queue[level] = Some(seg.segment(&rest));
- too_deep_area_may_have_dot_segments = false;
- end = seg.range.end;
- if level == 0 {
- first_segment_has_leading_slash = seg.has_leading_slash;
- }
- }
- level += 1;
- }
- }
- }
-
- // Write the path segments as possible, and update the internal state.
- for segname in queue.iter().flatten() {
- Self::emit_segment::<S, _>(
- f,
- &mut only_a_slash_is_written,
- first_segment_has_leading_slash,
- segname,
- authority_is_present,
- op,
- )?;
- }
-
- rest.remove_start(end);
- }
-
- if !rest.is_empty() {
- // No need of searching dot segments anymore.
- assert!(
- !too_deep_area_may_have_dot_segments,
- "[consistency] loop condition of the previous loop"
- );
- // Apply only normalization (if needed).
- for seg in PathSegmentsIter::new(&rest) {
- assert_eq!(
- seg.kind(&rest),
- SegmentKind::Normal,
- "[consistency] already confirmed that there are no more dot segments"
- );
- let segname = seg.segment(&rest);
- Self::emit_segment::<S, _>(
- f,
- &mut only_a_slash_is_written,
- seg.has_leading_slash,
- segname,
- authority_is_present,
- op,
- )?;
- }
- }
-
- Ok(())
- }
-
- /// Emits a non-dot segment and update the current state.
- //
- // `first_segment_has_leading_slash` can be any value if the segment is not the first one.
- fn emit_segment<S: Spec, W: fmt::Write>(
- f: &mut W,
- only_a_slash_is_written: &mut Option<bool>,
- first_segment_has_leading_slash: bool,
- segname: &str,
- authority_is_present: bool,
- op: NormalizationOp,
- ) -> fmt::Result {
- // Omit the leading slash of the segment only if the segment is
- // the first one and marked as not having a leading slash.
- match *only_a_slash_is_written {
- None => {
- // First segment.
- // This pass can be possible if `./` is repeated `QUEUE_SIZE`
- // times at the beginning.
- if first_segment_has_leading_slash {
- f.write_char('/')?;
- }
- *only_a_slash_is_written =
- Some(first_segment_has_leading_slash && segname.is_empty());
- }
- Some(only_a_slash) => {
- if only_a_slash && !authority_is_present {
- // Apply serialization like WHATWG URL Standard.
- // This prevents `<scheme=foo>:<path=//bar>` from written as
- // `foo://bar`, which is interpreted as
- // `<scheme=foo>://<authority=bar>`. Prepending `./`, the
- // serialization result would be `foo:/.//bar`, which is safe.
- f.write_str("./")?;
- *only_a_slash_is_written = Some(false);
- }
- f.write_char('/')?;
- }
- }
-
- // Write the segment name.
- if op.mode.case_pct_normalization() {
- write!(f, "{}", PctCaseNormalized::<S>::new(segname))
- } else {
- f.write_str(segname)
- }
- }
-
- /// Checks if the path is normalizable by RFC 3986 algorithm when the authority is absent.
- ///
- /// Returns `Ok(())` when normalizable, returns `Err(_)` if not.
- pub(crate) fn ensure_rfc3986_normalizable_with_authority_absent(&self) -> Result<(), Error> {
- /// A sink to get the prefix of the input.
- #[derive(Default)]
- struct PrefixRetriever {
- /// The buffer to remember the prefix of the input.
- buf: [u8; 3],
- /// The next write position in the buffer.
- cursor: usize,
- }
- impl PrefixRetriever {
- /// Returns the read prefix data.
- #[inline]
- #[must_use]
- fn as_bytes(&self) -> &[u8] {
- &self.buf[..self.cursor]
- }
- }
- impl fmt::Write for PrefixRetriever {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- if !s.is_empty() && (self.cursor >= self.buf.len()) {
- // Enough bytes are read.
- return Err(fmt::Error);
- }
- self.buf[self.cursor..]
- .iter_mut()
- .zip(s.bytes())
- .for_each(|(dest, src)| *dest = src);
- self.cursor = self.cursor.saturating_add(s.len()).min(self.buf.len());
- Ok(())
- }
- }
-
- let mut prefix = PrefixRetriever::default();
- // The failure of this write indicates more than 3 characters are read.
- // This is safe to ignore since the check needs only 3 characters.
- let _ = self.fmt_write_normalize::<UriSpec, _>(
- &mut prefix,
- NormalizationOp {
- mode: NormalizationMode::None,
- },
- // Assume the authority is absent.
- false,
- );
-
- if prefix.as_bytes() == b"/./" {
- Err(Error::new())
- } else {
- Ok(())
- }
- }
-}
-
-/// Characteristic of a path.
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum PathCharacteristic {
- /// Absolute path, not special.
- CommonAbsolute,
- /// Absolute path, not special.
- CommonRelative,
- /// The first path segment of the relative path has one or more colon characters.
- RelativeFirstSegmentHasColon,
- /// The path starts with the double slash.
- StartsWithDoubleSlash,
-}
-
-impl PathCharacteristic {
- /// Returns true if the path is absolute.
- #[inline]
- #[must_use]
- pub(crate) fn is_absolute(self) -> bool {
- matches!(self, Self::CommonAbsolute | Self::StartsWithDoubleSlash)
- }
-
- /// Returns the characteristic of the path.
- pub(crate) fn from_path_to_display<S: Spec>(
- path: &PathToNormalize<'_>,
- op: NormalizationOp,
- authority_is_present: bool,
- ) -> Self {
- /// Dummy writer to get necessary values.
- #[derive(Default, Clone, Copy)]
- struct Writer {
- /// Result.
- result: Option<PathCharacteristic>,
- /// Whether the normalized path is absolute.
- is_absolute: Option<bool>,
- }
- impl fmt::Write for Writer {
- fn write_str(&mut self, mut s: &str) -> fmt::Result {
- if self.result.is_some() {
- // Nothing more to do.
- return Err(fmt::Error);
- }
- while !s.is_empty() {
- if self.is_absolute.is_none() {
- // The first input.
- match s.strip_prefix('/') {
- Some(rest) => {
- self.is_absolute = Some(true);
- s = rest;
- }
- None => {
- self.is_absolute = Some(false);
- }
- }
- continue;
- }
- if self.is_absolute == Some(true) {
- let result = if s.starts_with('/') {
- PathCharacteristic::StartsWithDoubleSlash
- } else {
- PathCharacteristic::CommonAbsolute
- };
- self.result = Some(result);
- return Err(fmt::Error);
- }
- // Processing the first segment of the relative path.
- match find_split_hole(s, b'/') {
- Some((first_seg, _rest)) => {
- let result = if first_seg.contains(':') {
- PathCharacteristic::RelativeFirstSegmentHasColon
- } else {
- PathCharacteristic::CommonRelative
- };
- self.result = Some(result);
- return Err(fmt::Error);
- }
- None => {
- // `s` might not be the complete first segment.
- if s.contains(':') {
- self.result =
- Some(PathCharacteristic::RelativeFirstSegmentHasColon);
- return Err(fmt::Error);
- }
- break;
- }
- }
- }
- Ok(())
- }
- }
-
- let mut writer = Writer::default();
- match path.fmt_write_normalize::<S, _>(&mut writer, op, authority_is_present) {
- // Empty path.
- Ok(_) => PathCharacteristic::CommonRelative,
- Err(_) => writer
- .result
- .expect("[consistency] the formatting quits early by `Err` when the check is done"),
- }
- }
-}
-
-/// Path segment kind.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum SegmentKind {
- /// `.` or the equivalents.
- Dot,
- /// `..` or the equivalents.
- DotDot,
- /// Other normal (not special) segments.
- Normal,
-}
-
-impl SegmentKind {
- /// Creates a new `SegmentKind` from the given segment name.
- #[must_use]
- fn from_segment(s: &str) -> Self {
- match s {
- "." | "%2E" | "%2e" => SegmentKind::Dot,
- ".." | ".%2E" | ".%2e" | "%2E." | "%2E%2E" | "%2E%2e" | "%2e." | "%2e%2E"
- | "%2e%2e" => SegmentKind::DotDot,
- _ => SegmentKind::Normal,
- }
- }
-}
-
-/// A segment with optional leading slash.
-#[derive(Debug, Clone)]
-struct PathSegment {
- /// Presence of a leading slash.
- has_leading_slash: bool,
- /// Range of the segment name (without any slashes).
- range: Range<usize>,
-}
-
-impl PathSegment {
- /// Returns the segment without any slashes.
- #[inline]
- #[must_use]
- fn segment<'a>(&self, path: &PathToNormalize<'a>) -> &'a str {
- if let Some(prefix) = path.0 {
- let prefix_len = prefix.len();
- if self.range.end <= prefix_len {
- &prefix[self.range.clone()]
- } else {
- let range = (self.range.start - prefix_len)..(self.range.end - prefix_len);
- &path.1[range]
- }
- } else {
- &path.1[self.range.clone()]
- }
- }
-
- /// Returns the segment kind.
- #[inline]
- #[must_use]
- fn kind(&self, path: &PathToNormalize<'_>) -> SegmentKind {
- SegmentKind::from_segment(self.segment(path))
- }
-}
-
-/// Iterator of path segments.
-struct PathSegmentsIter<'a> {
- /// Path.
- path: &'a PathToNormalize<'a>,
- /// Current cursor position.
- cursor: usize,
-}
-
-impl<'a> PathSegmentsIter<'a> {
- /// Creates a new iterator of path segments.
- #[inline]
- #[must_use]
- fn new(path: &'a PathToNormalize<'a>) -> Self {
- Self { path, cursor: 0 }
- }
-}
-
-impl Iterator for PathSegmentsIter<'_> {
- type Item = PathSegment;
-
- fn next(&mut self) -> Option<Self::Item> {
- let path_len = self.path.len();
- if self.cursor >= path_len {
- return None;
- }
- let has_leading_slash = self.path.byte_at(self.cursor) == Some(b'/');
-
- let prefix_len = self.path.len_prefix();
- if (prefix_len != 0) && (self.cursor == prefix_len - 1) {
- debug_assert!(has_leading_slash);
- let end = self.path.1.find('/').unwrap_or(self.path.1.len()) + prefix_len;
- self.cursor = end;
- return Some(PathSegment {
- has_leading_slash,
- range: prefix_len..end,
- });
- }
-
- if has_leading_slash {
- // Skip the leading slash.
- self.cursor += 1;
- };
- let start = self.cursor;
- self.cursor = self.path.find_next_slash(self.cursor).unwrap_or(path_len);
-
- Some(PathSegment {
- has_leading_slash,
- range: start..self.cursor,
- })
- }
-}
diff --git a/vendor/iri-string/src/normalize/pct_case.rs b/vendor/iri-string/src/normalize/pct_case.rs
deleted file mode 100644
index 75e0a777..00000000
--- a/vendor/iri-string/src/normalize/pct_case.rs
+++ /dev/null
@@ -1,358 +0,0 @@
-//! Percent-encoding normalization and case normalization.
-
-use core::cmp::Ordering;
-use core::fmt::{self, Write as _};
-use core::marker::PhantomData;
-
-use crate::format::eq_str_display;
-use crate::parser::char::{is_ascii_unreserved, is_unreserved, is_utf8_byte_continue};
-use crate::parser::str::{find_split_hole, take_first_char};
-use crate::parser::trusted::take_xdigits2;
-use crate::spec::Spec;
-
-/// Returns true if the given string is percent-encoding normalized and case
-/// normalized.
-///
-/// Note that normalization of ASCII-only host requires additional case
-/// normalization, so checking by this function is not sufficient for that case.
-pub(crate) fn is_pct_case_normalized<S: Spec>(s: &str) -> bool {
- eq_str_display(s, &PctCaseNormalized::<S>::new(s))
-}
-
-/// Returns a character for the slice.
-///
-/// Essentially equivalent to `core::str::from_utf8(bytes).unwrap().and_then(|s| s.get(0))`,
-/// but this function fully trusts that the input is a valid UTF-8 string with
-/// only one character.
-fn into_char_trusted(bytes: &[u8]) -> Result<char, ()> {
- /// The bit mask to get the content part in a continue byte.
- const CONTINUE_BYTE_MASK: u8 = 0b_0011_1111;
- /// Minimum valid values for a code point in a UTF-8 sequence of 2, 3, and 4 bytes.
- const MIN: [u32; 3] = [0x80, 0x800, 0x1_0000];
-
- let len = bytes.len();
- let c: u32 = match len {
- 2 => (u32::from(bytes[0] & 0b_0001_1111) << 6) | u32::from(bytes[1] & CONTINUE_BYTE_MASK),
- 3 => {
- (u32::from(bytes[0] & 0b_0000_1111) << 12)
- | (u32::from(bytes[1] & CONTINUE_BYTE_MASK) << 6)
- | u32::from(bytes[2] & CONTINUE_BYTE_MASK)
- }
- 4 => {
- (u32::from(bytes[0] & 0b_0000_0111) << 18)
- | (u32::from(bytes[1] & CONTINUE_BYTE_MASK) << 12)
- | (u32::from(bytes[2] & CONTINUE_BYTE_MASK) << 6)
- | u32::from(bytes[3] & CONTINUE_BYTE_MASK)
- }
- len => unreachable!(
- "[consistency] expected 2, 3, or 4 bytes for a character, but got {len} as the length"
- ),
- };
- if c < MIN[len - 2] {
- // Redundant UTF-8 encoding.
- return Err(());
- }
- // Can be an invalid Unicode code point.
- char::from_u32(c).ok_or(())
-}
-
-/// Writable as a normalized path segment percent-encoding IRI.
-///
-/// This wrapper does the things below when being formatted:
-///
-/// * Decode unnecessarily percent-encoded characters.
-/// * Convert alphabetic characters uppercase in percent-encoded triplets.
-///
-/// Note that this does not newly encode raw characters.
-///
-/// # Safety
-///
-/// The given string should be the valid path segment.
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct PctCaseNormalized<'a, S> {
- /// Valid segment name to normalize.
- segname: &'a str,
- /// Spec.
- _spec: PhantomData<fn() -> S>,
-}
-
-impl<'a, S: Spec> PctCaseNormalized<'a, S> {
- /// Creates a new `PctCaseNormalized` value.
- #[inline]
- #[must_use]
- pub(crate) fn new(source: &'a str) -> Self {
- Self {
- segname: source,
- _spec: PhantomData,
- }
- }
-}
-
-impl<S: Spec> fmt::Display for PctCaseNormalized<'_, S> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut rest = self.segname;
-
- 'outer_loop: while !rest.is_empty() {
- // Scan the next percent-encoded triplet.
- let (prefix, after_percent) = match find_split_hole(rest, b'%') {
- Some(v) => v,
- None => return f.write_str(rest),
- };
- // Write the string before the percent-encoded triplet.
- f.write_str(prefix)?;
- // Decode the percent-encoded triplet.
- let (first_decoded, after_first_triplet) = take_xdigits2(after_percent);
- rest = after_first_triplet;
-
- if first_decoded.is_ascii() {
- if is_ascii_unreserved(first_decoded) {
- // Unreserved. Print the decoded.
- f.write_char(char::from(first_decoded))?;
- } else {
- write!(f, "%{:02X}", first_decoded)?;
- }
- continue 'outer_loop;
- }
-
- // Continue byte cannot be the first byte of a character.
- if is_utf8_byte_continue(first_decoded) {
- write!(f, "%{:02X}", first_decoded)?;
- continue 'outer_loop;
- }
-
- // Get the expected length of decoded char.
- let expected_char_len = match (first_decoded & 0xf0).cmp(&0b1110_0000) {
- Ordering::Less => 2,
- Ordering::Equal => 3,
- Ordering::Greater => 4,
- };
-
- // Get continue bytes.
- let c_buf = &mut [first_decoded, 0, 0, 0][..expected_char_len];
- for (i, buf_dest) in c_buf[1..].iter_mut().enumerate() {
- match take_first_char(rest) {
- Some(('%', after_percent)) => {
- let (byte, after_triplet) = take_xdigits2(after_percent);
- if !is_utf8_byte_continue(byte) {
- // Note that `byte` can start the new string.
- // Leave the byte in the `rest` for next try (i.e.
- // don't update `rest` in this case).
- c_buf[..=i]
- .iter()
- .try_for_each(|b| write!(f, "%{:02X}", b))?;
- continue 'outer_loop;
- }
- *buf_dest = byte;
- rest = after_triplet;
- }
- // If the next character is not `%`, decoded bytes so far
- // won't be valid UTF-8 byte sequence.
- // Write the read percent-encoded triplets without decoding.
- // Note that all characters in `&c_buf[1..]` (if available)
- // will be decoded to "continue byte" of UTF-8, so they
- // cannot be the start of a valid UTF-8 byte sequence if
- // decoded.
- Some((c, after_percent)) => {
- c_buf[..=i]
- .iter()
- .try_for_each(|b| write!(f, "%{:02X}", b))?;
- f.write_char(c)?;
- rest = after_percent;
- continue 'outer_loop;
- }
- None => {
- c_buf[..=i]
- .iter()
- .try_for_each(|b| write!(f, "%{:02X}", b))?;
- // Reached the end of the string.
- break 'outer_loop;
- }
- }
- }
-
- // Decode the bytes into a character.
- match into_char_trusted(&c_buf[..expected_char_len]) {
- Ok(decoded_c) => {
- if is_unreserved::<S>(decoded_c) {
- // Unreserved. Print the decoded.
- f.write_char(decoded_c)?;
- } else {
- c_buf[0..expected_char_len]
- .iter()
- .try_for_each(|b| write!(f, "%{:02X}", b))?;
- }
- }
- Err(_) => {
- // Skip decoding of the entire sequence of pct-encoded triplets loaded
- // in `c_buf`. This is valid from the reasons below.
- //
- // * The first byte in `c_buf` is valid as the first byte, and it tells the
- // expected number of bytes for a code unit. The cases the bytes being too
- // short and the sequence being incomplete have already been handled, and
- // the execution does not reach here then.
- // * All of the non-first bytes are checked if they are valid as UTF8 continue
- // bytes by `is_utf8_byte_continue()`. If they're not, the decoding of
- // that codepoint is aborted and the bytes in the buffer are immediately
- // emitted as pct-encoded, and the execution does not reach here. This
- // means that the bytes in the current `c_buf` have passed these tests.
- // * Since all of the the non-first bytes are UTF8 continue bytes, any of
- // them cannot start the new valid UTF-8 byte sequence. This means that
- // if the bytes in the buffer does not consitute a valid UTF-8 bytes
- // sequence, the whole buffer can immediately be emmitted as pct-encoded.
-
- debug_assert!(
- c_buf[1..expected_char_len]
- .iter()
- .copied()
- .all(is_utf8_byte_continue),
- "[consistency] all non-first bytes have been \
- confirmed that they are UTF-8 continue bytes"
- );
- // Note that the first pct-encoded triplet is stripped from
- // `after_first_triplet`.
- rest = &after_first_triplet[((expected_char_len - 1) * 3)..];
- c_buf[0..expected_char_len]
- .iter()
- .try_for_each(|b| write!(f, "%{:02X}", b))?;
- }
- }
- }
-
- Ok(())
- }
-}
-
-/// Writable as a normalized ASCII-only `host` (and optionally `port` followed).
-#[derive(Debug, Clone, Copy)]
-pub(crate) struct NormalizedAsciiOnlyHost<'a> {
- /// Valid host (and additionaly port) to normalize.
- host_port: &'a str,
-}
-
-impl<'a> NormalizedAsciiOnlyHost<'a> {
- /// Creates a new `NormalizedAsciiOnlyHost` value.
- ///
- /// # Preconditions
- ///
- /// The given string should be the valid ASCII-only `host` or
- /// `host ":" port` after percent-encoding normalization.
- /// In other words, [`parser::trusted::is_ascii_only_host`] should return
- /// true for the given value.
- ///
- /// [`parser::trusted::is_ascii_only_host`]: `crate::parser::trusted::is_ascii_only_host`
- #[inline]
- #[must_use]
- pub(crate) fn new(host_port: &'a str) -> Self {
- Self { host_port }
- }
-}
-
-impl fmt::Display for NormalizedAsciiOnlyHost<'_> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut rest = self.host_port;
-
- while !rest.is_empty() {
- // Scan the next percent-encoded triplet.
- let (prefix, after_percent) = match find_split_hole(rest, b'%') {
- Some(v) => v,
- None => {
- return rest
- .chars()
- .try_for_each(|c| f.write_char(c.to_ascii_lowercase()));
- }
- };
- // Write the string before the percent-encoded triplet.
- prefix
- .chars()
- .try_for_each(|c| f.write_char(c.to_ascii_lowercase()))?;
- // Decode the percent-encoded triplet.
- let (first_decoded, after_triplet) = take_xdigits2(after_percent);
- rest = after_triplet;
-
- assert!(
- first_decoded.is_ascii(),
- "[consistency] this function requires ASCII-only host as an argument"
- );
-
- if is_ascii_unreserved(first_decoded) {
- // Unreserved. Convert to lowercase and print.
- f.write_char(char::from(first_decoded.to_ascii_lowercase()))?;
- } else {
- write!(f, "%{:02X}", first_decoded)?;
- }
- }
-
- Ok(())
- }
-}
-
-#[cfg(test)]
-#[cfg(feature = "alloc")]
-mod tests {
- use super::*;
-
- #[cfg(all(feature = "alloc", not(feature = "std")))]
- use alloc::string::ToString;
-
- use crate::spec::{IriSpec, UriSpec};
-
- #[test]
- fn invalid_utf8() {
- assert_eq!(
- PctCaseNormalized::<UriSpec>::new("%80%cc%cc%cc").to_string(),
- "%80%CC%CC%CC"
- );
- assert_eq!(
- PctCaseNormalized::<IriSpec>::new("%80%cc%cc%cc").to_string(),
- "%80%CC%CC%CC"
- );
- }
-
- #[test]
- fn iri_unreserved() {
- assert_eq!(
- PctCaseNormalized::<UriSpec>::new("%ce%b1").to_string(),
- "%CE%B1"
- );
- assert_eq!(
- PctCaseNormalized::<IriSpec>::new("%ce%b1").to_string(),
- "\u{03B1}"
- );
- }
-
- #[test]
- fn iri_middle_decode() {
- assert_eq!(
- PctCaseNormalized::<UriSpec>::new("%ce%ce%b1%b1").to_string(),
- "%CE%CE%B1%B1"
- );
- assert_eq!(
- PctCaseNormalized::<IriSpec>::new("%ce%ce%b1%b1").to_string(),
- "%CE\u{03B1}%B1"
- );
- }
-
- #[test]
- fn ascii_reserved() {
- assert_eq!(PctCaseNormalized::<UriSpec>::new("%3f").to_string(), "%3F");
- assert_eq!(PctCaseNormalized::<IriSpec>::new("%3f").to_string(), "%3F");
- }
-
- #[test]
- fn ascii_forbidden() {
- assert_eq!(
- PctCaseNormalized::<UriSpec>::new("%3c%3e").to_string(),
- "%3C%3E"
- );
- assert_eq!(
- PctCaseNormalized::<IriSpec>::new("%3c%3e").to_string(),
- "%3C%3E"
- );
- }
-
- #[test]
- fn ascii_unreserved() {
- assert_eq!(PctCaseNormalized::<UriSpec>::new("%7ea").to_string(), "~a");
- assert_eq!(PctCaseNormalized::<IriSpec>::new("%7ea").to_string(), "~a");
- }
-}
diff --git a/vendor/iri-string/src/parser.rs b/vendor/iri-string/src/parser.rs
deleted file mode 100644
index 35a4d475..00000000
--- a/vendor/iri-string/src/parser.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! Common stuff for parsing.
-
-pub(crate) mod char;
-pub(crate) mod str;
-pub(crate) mod trusted;
-pub(crate) mod validate;
diff --git a/vendor/iri-string/src/parser/char.rs b/vendor/iri-string/src/parser/char.rs
deleted file mode 100644
index 2455498e..00000000
--- a/vendor/iri-string/src/parser/char.rs
+++ /dev/null
@@ -1,323 +0,0 @@
-//! Characters.
-
-use crate::spec::Spec;
-
-/// A mask to test whether the character is continue character of `scheme`.
-// `ALPHA / DIGIT / "+" / "-" / "."`
-const MASK_SCHEME_CONTINUE: u8 = 1 << 0;
-
-/// A mask to test whether the character matches `unreserved`.
-// `unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"`
-const MASK_UNRESERVED: u8 = 1 << 1;
-
-/// A mask to test whether the character matches `gen-delims`.
-// `gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"`
-const MASK_GEN_DELIMS: u8 = 1 << 2;
-
-/// A mask to test whether the character matches `sub-delims`.
-// `sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="`
-const MASK_SUB_DELIMS: u8 = 1 << 3;
-
-/// A mask to test whether the character matches `pchar` (modulo percent-encoded bytes).
-// `pchar = unreserved / pct-encoded / sub-delims / ":" / "@"`
-const MASK_PCHAR: u8 = 1 << 4;
-
-/// A mask to test whether the character can appear in `query` and `fragment`.
-// `query = *( pchar / "/" / "?" )`
-// `fragment = *( pchar / "/" / "?" )`
-const MASK_FRAG_QUERY: u8 = 1 << 5;
-
-/// A mask to test whether the character can appear in `userinfo` and address of `IPvFuture`.
-// `userinfo = *( unreserved / pct-encoded / sub-delims / ":" )`
-const MASK_USERINFO_IPVFUTUREADDR: u8 = 1 << 6;
-
-/// A mask to test whether the character matches `pchar` (modulo percent-encoded bytes) or slash.
-const MASK_PCHAR_SLASH: u8 = 1 << 7;
-
-/// ASCII characters' properties.
-const TABLE: [u8; 128] = [
- 0b_0000_0000, // NUL
- 0b_0000_0000, // SOH
- 0b_0000_0000, // STX
- 0b_0000_0000, // ETX
- 0b_0000_0000, // EOT
- 0b_0000_0000, // ENQ
- 0b_0000_0000, // ACK
- 0b_0000_0000, // BEL
- 0b_0000_0000, // BS
- 0b_0000_0000, // HT
- 0b_0000_0000, // LF
- 0b_0000_0000, // VT
- 0b_0000_0000, // FF
- 0b_0000_0000, // CR
- 0b_0000_0000, // SO
- 0b_0000_0000, // SI
- 0b_0000_0000, // DLE
- 0b_0000_0000, // DC1
- 0b_0000_0000, // DC2
- 0b_0000_0000, // DC3
- 0b_0000_0000, // DC4
- 0b_0000_0000, // NAK
- 0b_0000_0000, // SYN
- 0b_0000_0000, // ETB
- 0b_0000_0000, // CAN
- 0b_0000_0000, // EM
- 0b_0000_0000, // SUB
- 0b_0000_0000, // ESC
- 0b_0000_0000, // FS
- 0b_0000_0000, // GS
- 0b_0000_0000, // RS
- 0b_0000_0000, // US
- 0b_0000_0000, // SPACE
- 0b_1111_1000, // !
- 0b_0000_0000, // "
- 0b_0000_0100, // #
- 0b_1111_1000, // $
- 0b_0000_0000, // %
- 0b_1111_1000, // &
- 0b_1111_1000, // '
- 0b_1111_1000, // (
- 0b_1111_1000, // )
- 0b_1111_1000, // *
- 0b_1111_1001, // +
- 0b_1111_1000, // ,
- 0b_1111_0011, // -
- 0b_1111_0011, // .
- 0b_1010_0100, // /
- 0b_1111_0011, // 0
- 0b_1111_0011, // 1
- 0b_1111_0011, // 2
- 0b_1111_0011, // 3
- 0b_1111_0011, // 4
- 0b_1111_0011, // 5
- 0b_1111_0011, // 6
- 0b_1111_0011, // 7
- 0b_1111_0011, // 8
- 0b_1111_0011, // 9
- 0b_1111_0100, // :
- 0b_1111_1000, // ;
- 0b_0000_0000, // <
- 0b_1111_1000, // =
- 0b_0000_0000, // >
- 0b_0010_0100, // ?
- 0b_1011_0100, // @
- 0b_1111_0011, // A
- 0b_1111_0011, // B
- 0b_1111_0011, // C
- 0b_1111_0011, // D
- 0b_1111_0011, // E
- 0b_1111_0011, // F
- 0b_1111_0011, // G
- 0b_1111_0011, // H
- 0b_1111_0011, // I
- 0b_1111_0011, // J
- 0b_1111_0011, // K
- 0b_1111_0011, // L
- 0b_1111_0011, // M
- 0b_1111_0011, // N
- 0b_1111_0011, // O
- 0b_1111_0011, // P
- 0b_1111_0011, // Q
- 0b_1111_0011, // R
- 0b_1111_0011, // S
- 0b_1111_0011, // T
- 0b_1111_0011, // U
- 0b_1111_0011, // V
- 0b_1111_0011, // W
- 0b_1111_0011, // X
- 0b_1111_0011, // Y
- 0b_1111_0011, // Z
- 0b_0000_0100, // [
- 0b_0000_0000, // \
- 0b_0000_0100, // ]
- 0b_0000_0000, // ^
- 0b_1111_0010, // _
- 0b_0000_0000, // `
- 0b_1111_0011, // a
- 0b_1111_0011, // b
- 0b_1111_0011, // c
- 0b_1111_0011, // d
- 0b_1111_0011, // e
- 0b_1111_0011, // f
- 0b_1111_0011, // g
- 0b_1111_0011, // h
- 0b_1111_0011, // i
- 0b_1111_0011, // j
- 0b_1111_0011, // k
- 0b_1111_0011, // l
- 0b_1111_0011, // m
- 0b_1111_0011, // n
- 0b_1111_0011, // o
- 0b_1111_0011, // p
- 0b_1111_0011, // q
- 0b_1111_0011, // r
- 0b_1111_0011, // s
- 0b_1111_0011, // t
- 0b_1111_0011, // u
- 0b_1111_0011, // v
- 0b_1111_0011, // w
- 0b_1111_0011, // x
- 0b_1111_0011, // y
- 0b_1111_0011, // z
- 0b_0000_0000, // {
- 0b_0000_0000, // |
- 0b_0000_0000, // }
- 0b_1111_0010, // ~
- 0b_0000_0000, // DEL
-];
-
-/// Returns `true` if the given ASCII character is allowed as continue character of `scheme` part.
-#[inline]
-#[must_use]
-pub(crate) const fn is_ascii_scheme_continue(c: u8) -> bool {
- (TABLE[c as usize] & MASK_SCHEME_CONTINUE) != 0
-}
-
-/// Returns `true` if the given ASCII character matches `unreserved`.
-#[inline]
-#[must_use]
-pub(crate) const fn is_ascii_unreserved(c: u8) -> bool {
- (TABLE[c as usize] & MASK_UNRESERVED) != 0
-}
-
-/// Returns true if the character is unreserved.
-#[inline]
-#[must_use]
-pub(crate) fn is_unreserved<S: Spec>(c: char) -> bool {
- if c.is_ascii() {
- is_ascii_unreserved(c as u8)
- } else {
- S::is_nonascii_char_unreserved(c)
- }
-}
-
-///// Returns `true` if the given ASCII character matches `gen-delims`.
-//#[inline]
-//#[must_use]
-//pub(crate) const fn is_ascii_gen_delims(c: u8) -> bool {
-// (TABLE[c as usize] & MASK_GEN_DELIMS) != 0
-//}
-
-///// Returns `true` if the given ASCII character matches `sub-delims`.
-//#[inline]
-//#[must_use]
-//pub(crate) const fn is_ascii_sub_delims(c: u8) -> bool {
-// (TABLE[c as usize] & MASK_SUB_DELIMS) != 0
-//}
-
-///// Returns `true` if the given ASCII character matches `reserved`.
-//#[inline]
-//#[must_use]
-//pub(crate) const fn is_ascii_reserved(c: u8) -> bool {
-// (TABLE[c as usize] & (MASK_GEN_DELIMS | MASK_SUB_DELIMS)) != 0
-//}
-
-/// Returns `true` if the given ASCII character matches `pchar` modulo `pct-encoded`.
-#[inline]
-#[must_use]
-pub(crate) const fn is_ascii_pchar(c: u8) -> bool {
- (TABLE[c as usize] & MASK_PCHAR) != 0
-}
-
-/// Returns `true` if the given ASCII character is allowed to appear in `query` and `fragment`.
-#[inline]
-#[must_use]
-pub(crate) const fn is_ascii_frag_query(c: u8) -> bool {
- (TABLE[c as usize] & MASK_FRAG_QUERY) != 0
-}
-
-/// Returns `true` if the given non-ASCII character is allowed to appear in `iquery`.
-#[inline]
-#[must_use]
-pub(crate) fn is_nonascii_query<S: Spec>(c: char) -> bool {
- S::is_nonascii_char_unreserved(c) || S::is_nonascii_char_private(c)
-}
-
-/// Returns `true` if the given non-ASCII character is allowed to appear in `ifragment`.
-#[inline]
-#[must_use]
-pub(crate) fn is_nonascii_fragment<S: Spec>(c: char) -> bool {
- S::is_nonascii_char_unreserved(c)
-}
-
-/// Returns `true` if the given ASCII character is allowed to appear in `userinfo` and `IPvFuture`.
-#[inline]
-#[must_use]
-pub(crate) const fn is_ascii_userinfo_ipvfutureaddr(c: u8) -> bool {
- (TABLE[c as usize] & MASK_USERINFO_IPVFUTUREADDR) != 0
-}
-
-/// Returns `true` if the given non-ASCII character is allowed to appear in `iuserinfo`.
-#[inline]
-#[must_use]
-pub(crate) fn is_nonascii_userinfo<S: Spec>(c: char) -> bool {
- S::is_nonascii_char_unreserved(c)
-}
-
-/// Returns `true` if the given ASCII character is allowed to appear in `reg-name`
-#[inline]
-#[must_use]
-pub(crate) const fn is_ascii_regname(c: u8) -> bool {
- (TABLE[c as usize] & (MASK_UNRESERVED | MASK_SUB_DELIMS)) != 0
-}
-
-/// Returns `true` if the given non-ASCII character is allowed to appear in `ireg-name`.
-#[inline]
-#[must_use]
-pub(crate) fn is_nonascii_regname<S: Spec>(c: char) -> bool {
- S::is_nonascii_char_unreserved(c)
-}
-
-/// Returns `true` if the given ASCII character matches `pchar` modulo `pct-encoded` or a slash.
-#[inline]
-#[must_use]
-pub(crate) const fn is_ascii_pchar_slash(c: u8) -> bool {
- (TABLE[c as usize] & MASK_PCHAR_SLASH) != 0
-}
-
-/// Checks if the given character matches `ucschar` rule.
-#[must_use]
-pub(crate) fn is_ucschar(c: char) -> bool {
- matches!(
- u32::from(c),
- 0xA0..=0xD7FF |
- 0xF900..=0xFDCF |
- 0xFDF0..=0xFFEF |
- 0x1_0000..=0x1_FFFD |
- 0x2_0000..=0x2_FFFD |
- 0x3_0000..=0x3_FFFD |
- 0x4_0000..=0x4_FFFD |
- 0x5_0000..=0x5_FFFD |
- 0x6_0000..=0x6_FFFD |
- 0x7_0000..=0x7_FFFD |
- 0x8_0000..=0x8_FFFD |
- 0x9_0000..=0x9_FFFD |
- 0xA_0000..=0xA_FFFD |
- 0xB_0000..=0xB_FFFD |
- 0xC_0000..=0xC_FFFD |
- 0xD_0000..=0xD_FFFD |
- 0xE_1000..=0xE_FFFD
- )
-}
-
-/// Returns true if the given value is a continue byte of UTF-8.
-#[inline(always)]
-#[must_use]
-pub(crate) fn is_utf8_byte_continue(byte: u8) -> bool {
- // `0x80..=0xbf` (i.e. `0b_1000_0000..=0b_1011_1111`) is not the first byte,
- // and `0xc0..=0xc1` (i.e. `0b_1100_0000..=0b_1100_0001` shouldn't appear
- // anywhere in UTF-8 byte sequence.
- // `0x80 as i8` is -128, and `0xc0 as i8` is -96.
- //
- // The first byte of the UTF-8 character is not `0b10xx_xxxx`, and
- // the continue bytes is `0b10xx_xxxx`.
- // `0b1011_1111 as i8` is -65, and `0b1000_0000 as i8` is -128.
- (byte as i8) < -64
-}
-
-/// Returns true if the given ASCII character is `unreserved` or `reserved`.
-#[inline]
-#[must_use]
-pub(crate) const fn is_ascii_unreserved_or_reserved(c: u8) -> bool {
- (TABLE[c as usize] & (MASK_UNRESERVED | MASK_GEN_DELIMS | MASK_SUB_DELIMS)) != 0
-}
diff --git a/vendor/iri-string/src/parser/str.rs b/vendor/iri-string/src/parser/str.rs
deleted file mode 100644
index 0f564bfa..00000000
--- a/vendor/iri-string/src/parser/str.rs
+++ /dev/null
@@ -1,390 +0,0 @@
-//! Functions for common string operations.
-
-pub(crate) use self::maybe_pct_encoded::{
- process_percent_encoded_best_effort, PctEncodedFragments,
-};
-
-mod maybe_pct_encoded;
-
-/// Returns the inner string if wrapped.
-#[must_use]
-pub(crate) fn get_wrapped_inner(s: &str, open: u8, close: u8) -> Option<&str> {
- let (prefix, suffix) = match s.as_bytes() {
- [prefix, suffix] | [prefix, .., suffix] => (*prefix, *suffix),
- _ => return None,
- };
- if (prefix == open) && (suffix == close) {
- Some(&s[1..(s.len() - 1)])
- } else {
- None
- }
-}
-
-/// Returns the byte that appears first.
-#[cfg(not(feature = "memchr"))]
-#[inline]
-#[must_use]
-pub(crate) fn prior_byte2(haystack: &[u8], needle1: u8, needle2: u8) -> Option<u8> {
- haystack
- .iter()
- .copied()
- .find(|&b| b == needle1 || b == needle2)
-}
-
-/// Returns the byte that appears first.
-#[cfg(feature = "memchr")]
-#[inline]
-#[must_use]
-pub(crate) fn prior_byte2(haystack: &[u8], needle1: u8, needle2: u8) -> Option<u8> {
- memchr::memchr2(needle1, needle2, haystack).map(|pos| haystack[pos])
-}
-
-/// (Possibly) faster version of `haystack.rfind(needle)` when `needle` is an ASCII character.
-#[cfg(not(feature = "memchr"))]
-#[inline]
-#[must_use]
-pub(crate) fn rfind(haystack: &[u8], needle: u8) -> Option<usize> {
- haystack.iter().rposition(|&b| b == needle)
-}
-
-/// (Possibly) faster version of `haystack.rfind(needle)` when `needle` is an ASCII character.
-#[cfg(feature = "memchr")]
-#[inline]
-#[must_use]
-pub(crate) fn rfind(haystack: &[u8], needle: u8) -> Option<usize> {
- memchr::memrchr(needle, haystack)
-}
-
-/// Finds the first needle, and returns the string before it and the rest.
-///
-/// If `needle` is not found, returns `None`.
-#[cfg(not(feature = "memchr"))]
-#[must_use]
-pub(crate) fn find_split(haystack: &str, needle: u8) -> Option<(&str, &str)> {
- haystack
- .bytes()
- .position(|b| b == needle)
- .map(|pos| haystack.split_at(pos))
-}
-
-/// Finds the first needle, and returns the string before it and the rest.
-///
-/// If `needle` is not found, returns `None`.
-#[cfg(feature = "memchr")]
-#[must_use]
-pub(crate) fn find_split(haystack: &str, needle: u8) -> Option<(&str, &str)> {
- memchr::memchr(needle, haystack.as_bytes()).map(|pos| haystack.split_at(pos))
-}
-
-/// Finds the last needle, and returns the string before it and the rest.
-///
-/// If no needles are found, returns `None`.
-#[cfg(not(feature = "memchr"))]
-#[must_use]
-pub(crate) fn rfind_split2(haystack: &str, needle1: u8, needle2: u8) -> Option<(&str, &str)> {
- haystack
- .bytes()
- .rposition(|b| b == needle1 || b == needle2)
- .map(|pos| haystack.split_at(pos))
-}
-
-/// Finds the last needle, and returns the string before it and the rest.
-///
-/// If no needles are found, returns `None`.
-#[cfg(feature = "memchr")]
-#[must_use]
-pub(crate) fn rfind_split2(haystack: &str, needle1: u8, needle2: u8) -> Option<(&str, &str)> {
- memchr::memrchr2(needle1, needle2, haystack.as_bytes()).map(|pos| haystack.split_at(pos))
-}
-
-/// Finds the first needle, and returns the string before it and the rest.
-///
-/// If no needles are found, returns `None`.
-#[cfg(not(feature = "memchr"))]
-#[must_use]
-pub(crate) fn find_split2(haystack: &str, needle1: u8, needle2: u8) -> Option<(&str, &str)> {
- haystack
- .bytes()
- .position(|b| b == needle1 || b == needle2)
- .map(|pos| haystack.split_at(pos))
-}
-
-/// Finds the first needle, and returns the string before it and the rest.
-///
-/// If no needles are found, returns `None`.
-#[cfg(feature = "memchr")]
-#[must_use]
-pub(crate) fn find_split2(haystack: &str, needle1: u8, needle2: u8) -> Option<(&str, &str)> {
- memchr::memchr2(needle1, needle2, haystack.as_bytes()).map(|pos| haystack.split_at(pos))
-}
-
-/// Finds the first needle, and returns the string before it and the rest.
-///
-/// If no needles are found, returns `None`.
-#[cfg(not(feature = "memchr"))]
-#[must_use]
-pub(crate) fn find_split3(
- haystack: &str,
- needle1: u8,
- needle2: u8,
- needle3: u8,
-) -> Option<(&str, &str)> {
- haystack
- .bytes()
- .position(|b| b == needle1 || b == needle2 || b == needle3)
- .map(|pos| haystack.split_at(pos))
-}
-
-/// Finds the first needle, and returns the string before it and the rest.
-///
-/// If no needles are found, returns `None`.
-#[cfg(feature = "memchr")]
-#[must_use]
-pub(crate) fn find_split3(
- haystack: &str,
- needle1: u8,
- needle2: u8,
- needle3: u8,
-) -> Option<(&str, &str)> {
- memchr::memchr3(needle1, needle2, needle3, haystack.as_bytes())
- .map(|pos| haystack.split_at(pos))
-}
-
-/// Finds the first needle, and returns the string before it and after it.
-///
-/// If `needle` is not found, returns `None`.
-#[cfg(not(feature = "memchr"))]
-#[must_use]
-pub(crate) fn find_split_hole(haystack: &str, needle: u8) -> Option<(&str, &str)> {
- haystack
- .bytes()
- .position(|b| b == needle)
- .map(|pos| (&haystack[..pos], &haystack[(pos + 1)..]))
-}
-
-/// Finds the first needle, and returns the string before it and after it.
-///
-/// If `needle` is not found, returns `None`.
-#[cfg(feature = "memchr")]
-#[must_use]
-pub(crate) fn find_split_hole(haystack: &str, needle: u8) -> Option<(&str, &str)> {
- memchr::memchr(needle, haystack.as_bytes())
- .map(|pos| (&haystack[..pos], &haystack[(pos + 1)..]))
-}
-
-/// Finds the first needle, and returns the string before it, the needle, and the string after it.
-///
-/// If no needles are found, returns `None`.
-#[cfg(not(feature = "memchr"))]
-#[must_use]
-pub(crate) fn find_split2_hole(
- haystack: &str,
- needle1: u8,
- needle2: u8,
-) -> Option<(&str, u8, &str)> {
- haystack
- .bytes()
- .position(|b| b == needle1 || b == needle2)
- .map(|pos| {
- (
- &haystack[..pos],
- haystack.as_bytes()[pos],
- &haystack[(pos + 1)..],
- )
- })
-}
-
-/// Finds the first needle, and returns the string before it, the needle, and the string after it.
-///
-/// If no needles are found, returns `None`.
-#[cfg(feature = "memchr")]
-#[must_use]
-pub(crate) fn find_split2_hole(
- haystack: &str,
- needle1: u8,
- needle2: u8,
-) -> Option<(&str, u8, &str)> {
- memchr::memchr2(needle1, needle2, haystack.as_bytes()).map(|pos| {
- (
- &haystack[..pos],
- haystack.as_bytes()[pos],
- &haystack[(pos + 1)..],
- )
- })
-}
-
-/// Finds the first needle, and returns the string before it, the needle, and the string after it.
-///
-/// If no needles are found, returns `None`.
-#[cfg(not(feature = "memchr"))]
-#[must_use]
-pub(crate) fn find_split4_hole(
- haystack: &str,
- needle1: u8,
- needle2: u8,
- needle3: u8,
- needle4: u8,
-) -> Option<(&str, u8, &str)> {
- haystack
- .bytes()
- .position(|b| b == needle1 || b == needle2 || b == needle3 || b == needle4)
- .map(|pos| {
- (
- &haystack[..pos],
- haystack.as_bytes()[pos],
- &haystack[(pos + 1)..],
- )
- })
-}
-
-/// Finds the first needle, and returns the string before it, the needle, and the string after it.
-///
-/// If no needles are found, returns `None`.
-#[cfg(feature = "memchr")]
-#[must_use]
-pub(crate) fn find_split4_hole(
- haystack: &str,
- needle1: u8,
- needle2: u8,
- needle3: u8,
- needle4: u8,
-) -> Option<(&str, u8, &str)> {
- let bytes = haystack.as_bytes();
- let pos = match memchr::memchr3(needle1, needle2, needle3, bytes) {
- Some(prefix_len) => memchr::memchr(needle4, &bytes[..prefix_len]).or(Some(prefix_len)),
- None => memchr::memchr(needle4, bytes),
- };
- pos.map(|pos| {
- (
- &haystack[..pos],
- haystack.as_bytes()[pos],
- &haystack[(pos + 1)..],
- )
- })
-}
-
-/// Finds the last needle, and returns the string before it and after it.
-///
-/// If `needle` is not found, returns `None`.
-#[cfg(not(feature = "memchr"))]
-#[must_use]
-pub(crate) fn rfind_split_hole(haystack: &str, needle: u8) -> Option<(&str, &str)> {
- haystack
- .bytes()
- .rposition(|b| b == needle)
- .map(|pos| (&haystack[..pos], &haystack[(pos + 1)..]))
-}
-
-/// Finds the last needle, and returns the string before it and after it.
-///
-/// If `needle` is not found, returns `None`.
-#[cfg(feature = "memchr")]
-#[must_use]
-pub(crate) fn rfind_split_hole(haystack: &str, needle: u8) -> Option<(&str, &str)> {
- memchr::memrchr(needle, haystack.as_bytes())
- .map(|pos| (&haystack[..pos], &haystack[(pos + 1)..]))
-}
-
-/// Returns `true` if the string only contains the allowed characters.
-#[must_use]
-fn satisfy_chars<F, G>(mut s: &str, pred_ascii: F, pred_nonascii: G) -> bool
-where
- F: Copy + Fn(u8) -> bool,
- G: Copy + Fn(char) -> bool,
-{
- while !s.is_empty() {
- match s.bytes().position(|b| !b.is_ascii()) {
- Some(nonascii_pos) => {
- // Valdiate ASCII prefix.
- if nonascii_pos != 0 {
- let (prefix, rest) = s.split_at(nonascii_pos);
- if !prefix.bytes().all(pred_ascii) {
- return false;
- }
- s = rest;
- }
-
- // Extract non-ASCII part and validate it.
- let (prefix, rest) = match s.bytes().position(|b| b.is_ascii()) {
- Some(ascii_pos) => s.split_at(ascii_pos),
- None => (s, ""),
- };
- if !prefix.chars().all(pred_nonascii) {
- return false;
- }
- s = rest;
- }
- None => {
- // All chars are ASCII.
- return s.bytes().all(pred_ascii);
- }
- }
- }
-
- true
-}
-
-/// Returns `true` if the string only contains the allowed characters and percent-encoded char.
-#[must_use]
-pub(crate) fn satisfy_chars_with_pct_encoded<F, G>(
- mut s: &str,
- pred_ascii: F,
- pred_nonascii: G,
-) -> bool
-where
- F: Copy + Fn(u8) -> bool,
- G: Copy + Fn(char) -> bool,
-{
- while let Some((prefix, suffix)) = find_split_hole(s, b'%') {
- // Verify strings before the percent-encoded char.
- if !prefix.is_empty() && !satisfy_chars(prefix, pred_ascii, pred_nonascii) {
- return false;
- }
-
- // Verify the percent-encoded char.
- if !starts_with_double_hexdigits(suffix.as_bytes()) {
- return false;
- }
-
- // Advance the cursor.
- s = &suffix[2..];
- }
-
- // Verify the rest.
- satisfy_chars(s, pred_ascii, pred_nonascii)
-}
-
-/// Returns `true` if the given string starts with two hexadecimal digits.
-#[must_use]
-pub(crate) fn starts_with_double_hexdigits(s: &[u8]) -> bool {
- match s {
- [x, y] | [x, y, ..] => x.is_ascii_hexdigit() && y.is_ascii_hexdigit(),
- _ => false,
- }
-}
-
-/// Strips the first character if it is the given ASCII character, and returns the rest.
-///
-/// # Precondition
-///
-/// The given ASCII character (`prefix`) should be an ASCII character.
-#[must_use]
-pub(crate) fn strip_ascii_char_prefix(s: &str, prefix: u8) -> Option<&str> {
- debug_assert!(prefix.is_ascii());
- if s.as_bytes().first().copied() == Some(prefix) {
- Some(&s[1..])
- } else {
- None
- }
-}
-
-/// Splits the given string into the first character and the rest.
-///
-/// Returns `(first_char, rest_str)`.
-#[must_use]
-pub(crate) fn take_first_char(s: &str) -> Option<(char, &str)> {
- let mut chars = s.chars();
- let c = chars.next()?;
- let rest = chars.as_str();
- Some((c, rest))
-}
diff --git a/vendor/iri-string/src/parser/str/maybe_pct_encoded.rs b/vendor/iri-string/src/parser/str/maybe_pct_encoded.rs
deleted file mode 100644
index 617f006a..00000000
--- a/vendor/iri-string/src/parser/str/maybe_pct_encoded.rs
+++ /dev/null
@@ -1,369 +0,0 @@
-//! Processor for possibly- or invalidly-percent-encoded strings.
-
-use core::fmt::{self, Write as _};
-use core::marker::PhantomData;
-use core::num::NonZeroU8;
-use core::ops::ControlFlow;
-
-use crate::parser::str::find_split;
-use crate::parser::trusted::hexdigits_to_byte;
-
-/// Fragment in a possibly percent-encoded (and possibly broken) string.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum PctEncodedFragments<'a> {
- /// String fragment without percent-encoded triplets.
- NoPctStr(&'a str),
- /// Stray `%` (percent) character.
- StrayPercent,
- /// Valid percent-encoded triplets for a character.
- Char(&'a str, char),
- /// Percent-encoded triplets that does not consists of a valid UTF-8 sequence.
- InvalidUtf8PctTriplets(&'a str),
-}
-
-/// Processes characters in a string which may contain (possibly invalid) percent-encoded triplets.
-pub(crate) fn process_percent_encoded_best_effort<T, F, B>(
- v: T,
- mut f: F,
-) -> Result<ControlFlow<B>, fmt::Error>
-where
- T: fmt::Display,
- F: FnMut(PctEncodedFragments<'_>) -> ControlFlow<B>,
-{
- let mut buf = [0_u8; 12];
- let mut writer = DecomposeWriter {
- f: &mut f,
- decoder: Default::default(),
- buf: &mut buf,
- result: ControlFlow::Continue(()),
- _r: PhantomData,
- };
-
- if write!(writer, "{v}").is_err() {
- match writer.result {
- ControlFlow::Continue(_) => return Err(fmt::Error),
- ControlFlow::Break(v) => return Ok(ControlFlow::Break(v)),
- }
- }
-
- // Flush the internal buffer of the decoder.
- if let Some(len) = writer.decoder.flush(&mut buf).map(|v| usize::from(v.get())) {
- let len_suffix = len % 3;
- let triplets_end = len - len_suffix;
- let triplets = core::str::from_utf8(&buf[..triplets_end])
- .expect("[validity] percent-encoded triplets consist of ASCII characters");
- if let ControlFlow::Break(v) = f(PctEncodedFragments::InvalidUtf8PctTriplets(triplets)) {
- return Ok(ControlFlow::Break(v));
- }
-
- if len_suffix > 0 {
- if let ControlFlow::Break(v) = f(PctEncodedFragments::StrayPercent) {
- return Ok(ControlFlow::Break(v));
- }
- }
- if len_suffix > 1 {
- let after_percent = core::str::from_utf8(
- &buf[(triplets_end + 1)..(triplets_end + len_suffix)],
- )
- .expect("[consistency] percent-encoded triplets contains only ASCII characters");
- if let ControlFlow::Break(v) = f(PctEncodedFragments::NoPctStr(after_percent)) {
- return Ok(ControlFlow::Break(v));
- }
- }
- }
-
- Ok(ControlFlow::Continue(()))
-}
-
-/// Writer to decompose the input into fragments.
-struct DecomposeWriter<'a, F, B> {
- /// Output function.
- f: &'a mut F,
- /// Decoder.
- decoder: DecoderBuffer,
- /// Buffer.
- buf: &'a mut [u8],
- /// Result of the last output function call.
- result: ControlFlow<B>,
- /// Dummy field for the type parameter of the return type of the function `f`.
- _r: PhantomData<fn() -> B>,
-}
-impl<F, B> DecomposeWriter<'_, F, B>
-where
- F: FnMut(PctEncodedFragments<'_>) -> ControlFlow<B>,
-{
- /// Returns `Ok(_)` if the stored result is `Continue`, and `Err(_)` otherwise.
- #[inline(always)]
- fn result_continue_or_err(&self) -> fmt::Result {
- if self.result.is_break() {
- return Err(fmt::Error);
- }
- Ok(())
- }
-
- /// Calls the output functions with the undecodable fragments.
- fn output_as_undecodable(&mut self, len_undecodable: u8) -> fmt::Result {
- let len_written = usize::from(len_undecodable);
- let frag = core::str::from_utf8(&self.buf[..len_written])
- .expect("[validity] `DecoderBuffer` writes a valid ASCII string");
- let len_incomplete = len_written % 3;
- let len_complete = len_written - len_incomplete;
- self.result = (self.f)(PctEncodedFragments::InvalidUtf8PctTriplets(
- &frag[..len_complete],
- ));
- self.result_continue_or_err()?;
- if len_incomplete > 0 {
- // At least the first `%` exists.
- self.result = (self.f)(PctEncodedFragments::StrayPercent);
- if self.result.is_break() {
- return Err(fmt::Error);
- }
- if len_incomplete > 1 {
- // A following hexdigit is available.
- debug_assert_eq!(
- len_incomplete, 2,
- "[consistency] the length of incomplete percent-encoded \
- triplet must be less than 2 bytes"
- );
- self.result = (self.f)(PctEncodedFragments::NoPctStr(
- &frag[(len_complete + 1)..len_written],
- ));
- self.result_continue_or_err()?;
- }
- }
- Ok(())
- }
-}
-
-impl<F, B> fmt::Write for DecomposeWriter<'_, F, B>
-where
- F: FnMut(PctEncodedFragments<'_>) -> ControlFlow<B>,
-{
- fn write_str(&mut self, s: &str) -> fmt::Result {
- self.result_continue_or_err()?;
- let mut rest = s;
- while !rest.is_empty() {
- let (len_consumed, result) = self.decoder.push_encoded(self.buf, rest);
- if len_consumed == 0 {
- // `rest` does not start with the percent-encoded triplets.
- // Flush the decoder before attempting to decode more data.
- if let Some(len_written) = self.decoder.flush(self.buf).map(NonZeroU8::get) {
- self.output_as_undecodable(len_written)?;
- rest = &rest[usize::from(len_written)..];
- }
-
- // Write plain string prefix (if found).
- let (plain_prefix, suffix) = find_split(rest, b'%').unwrap_or((rest, ""));
- debug_assert!(
- !plain_prefix.is_empty(),
- "[consistency] `len_consumed == 0` indicates non-empty \
- `rest` not starting with `%`"
- );
- self.result = (self.f)(PctEncodedFragments::NoPctStr(plain_prefix));
- self.result_continue_or_err()?;
- rest = suffix;
- continue;
- }
-
- // Process decoding result.
- match result {
- PushResult::Decoded(len_written, c) => {
- let len_written = usize::from(len_written.get());
- let frag = core::str::from_utf8(&self.buf[..len_written])
- .expect("[validity] `DecoderBuffer` writes a valid ASCII string");
- self.result = (self.f)(PctEncodedFragments::Char(frag, c));
- self.result_continue_or_err()?;
- }
- PushResult::Undecodable(len_written) => {
- self.output_as_undecodable(len_written)?;
- }
- PushResult::NeedMoreBytes => {
- // Nothing to write at this time.
- }
- }
- rest = &rest[len_consumed..];
- }
- Ok(())
- }
-}
-
-/// A type for result of feeding data to [`DecoderBuffer`].
-#[derive(Debug, Clone, Copy)]
-enum PushResult {
- /// Input is still incomplete, needs more bytes to get the decoding result.
- NeedMoreBytes,
- /// Bytes decodable to valid UTF-8 sequence.
- // `.0`: Length of decodable fragment.
- // `.1`: Decoded character.
- Decoded(NonZeroU8, char),
- /// Valid percent-encoded triplets but not decodable to valid UTF-8 sequence.
- // `.0`: Length of undecodable fragment.
- Undecodable(u8),
-}
-
-/// Buffer to contain (and to decode) incomplete percent-encoded triplets.
-#[derive(Default, Debug, Clone, Copy)]
-struct DecoderBuffer {
- /// Percent-encoded triplets that possibly consists a valid UTF-8 sequence after decoded.
- //
- // `3 * 4`: 3 ASCII characters for single percent-encoded triplet, and
- // 4 triplets at most for single Unicode codepoint in UTF-8.
- encoded: [u8; 12],
- /// Decoded bytes.
- decoded: [u8; 4],
- /// Number of bytes available in `buf_encoded` buffer.
- ///
- /// `buf_encoded_len / 3` also indicates the length of data in `decoded`.
- len_encoded: u8,
-}
-
-impl DecoderBuffer {
- /// Writes the data of the given length to the destination, and remove that part from buffer.
- fn write_and_pop(&mut self, dest: &mut [u8], remove_len: u8) {
- let new_len = self.len_encoded - remove_len;
- let remove_len = usize::from(remove_len);
- let src_range = remove_len..usize::from(self.len_encoded);
- dest[..remove_len].copy_from_slice(&self.encoded[..remove_len]);
-
- if new_len == 0 {
- *self = Self::default();
- return;
- }
- self.encoded.copy_within(src_range, 0);
- self.decoded
- .copy_within((remove_len / 3)..usize::from(self.len_encoded / 3), 0);
- self.len_encoded = new_len;
- }
-
- /// Pushes a byte of a (possible) percent-encoded tripet to the buffer.
- fn push_single_encoded_byte(&mut self, byte: u8) {
- debug_assert!(
- self.len_encoded < 12,
- "[consistency] four percent-encoded triplets are enough for a unicode code point"
- );
- let pos_enc = usize::from(self.len_encoded);
- self.len_encoded += 1;
- self.encoded[pos_enc] = byte;
- if self.len_encoded % 3 == 0 {
- // A new percent-encoded triplet is read. Decode and remember.
- let pos_dec = usize::from(self.len_encoded / 3 - 1);
- let upper = self.encoded[pos_enc - 1];
- let lower = byte;
- debug_assert!(
- upper.is_ascii_hexdigit() && lower.is_ascii_hexdigit(),
- "[consistency] the `encoded` buffer should contain valid percent-encoded triplets"
- );
- self.decoded[pos_dec] = hexdigits_to_byte([upper, lower]);
- }
- }
-
- /// Pushes the (possibly) encoded string to the buffer.
- ///
- /// When the push result is not `PctTripletPushResult::NeedMoreBytes`, the
- /// caller should call `Self::clear()` before pushing more bytes.
- ///
- /// # Preconditions
- ///
- /// * `buf` should be more than 12 bytes. If not, this method may panic.
- #[must_use]
- pub(crate) fn push_encoded(&mut self, buf: &mut [u8], s: &str) -> (usize, PushResult) {
- debug_assert!(
- buf.len() >= 12,
- "[internal precondition] destination buffer should be at least 12 bytes"
- );
- let mut chars = s.chars();
- let mut len_triplet_incomplete = self.len_encoded % 3;
- for c in &mut chars {
- if len_triplet_incomplete == 0 {
- // Expect `%`.
- if c != '%' {
- // Undecodable.
- // `-1`: the last byte is peeked but not consumed.
- let len_consumed = s.len() - chars.as_str().len() - 1;
- let len_result = self.len_encoded;
- self.write_and_pop(buf, len_result);
- return (len_consumed, PushResult::Undecodable(len_result));
- }
- self.push_single_encoded_byte(b'%');
- len_triplet_incomplete = 1;
- continue;
- }
-
- // Expect a nibble.
- if !c.is_ascii_hexdigit() {
- // Undecodable.
- // `-1`: the last byte is peeked but not consumed.
- let len_consumed = s.len() - chars.as_str().len() - 1;
- let len_result = self.len_encoded;
- self.write_and_pop(buf, len_result);
- return (len_consumed, PushResult::Undecodable(len_result));
- }
- self.push_single_encoded_byte(c as u8);
- if len_triplet_incomplete == 1 {
- len_triplet_incomplete = 2;
- continue;
- } else {
- // Now a new percent-encoded triplet is read!
- debug_assert_eq!(len_triplet_incomplete, 2);
- len_triplet_incomplete = 0;
- }
-
- // Now a new percent-encoded triplet is read.
- // Check if the buffer contains a valid decodable content.
- let len_decoded = usize::from(self.len_encoded) / 3;
- match core::str::from_utf8(&self.decoded[..len_decoded]) {
- Ok(decoded_str) => {
- // Successfully decoded.
- let len_consumed = s.len() - chars.as_str().len();
- let c = decoded_str
- .chars()
- .next()
- .expect("[validity] `decoded` buffer is nonempty");
- let len_result = NonZeroU8::new(self.len_encoded).expect(
- "[consistency] `encoded` buffer is nonempty since \
- `push_single_encoded_byte()` was called",
- );
- self.write_and_pop(buf, len_result.get());
- return (len_consumed, PushResult::Decoded(len_result, c));
- }
- Err(e) => {
- // Undecodable.
- assert_eq!(
- e.valid_up_to(),
- 0,
- "[consistency] `decoded` buffer contains at most one character"
- );
- let skip_len_decoded = match e.error_len() {
- // Unexpected EOF. Wait for remaining input.
- None => continue,
- // Skip invalid bytes.
- Some(v) => v,
- };
- let len_consumed = s.len() - chars.as_str().len();
- let len_result = skip_len_decoded as u8 * 3;
- assert_ne!(
- skip_len_decoded, 0,
- "[consistency] empty bytes cannot be invalid"
- );
- self.write_and_pop(buf, len_result);
- return (len_consumed, PushResult::Undecodable(len_result));
- }
- };
- }
- let len_consumed = s.len() - chars.as_str().len();
- (len_consumed, PushResult::NeedMoreBytes)
- }
-
- /// Writes the incomplete data completely to the destination, and clears the internal buffer.
- #[must_use]
- pub(crate) fn flush(&mut self, buf: &mut [u8]) -> Option<NonZeroU8> {
- let len_result = NonZeroU8::new(self.len_encoded)?;
- // Emit the current (undecodable) buffer as is.
- self.write_and_pop(buf, len_result.get());
- debug_assert_eq!(
- self.len_encoded, 0,
- "[consistency] the buffer should be cleared after flushed"
- );
- Some(len_result)
- }
-}
diff --git a/vendor/iri-string/src/parser/trusted.rs b/vendor/iri-string/src/parser/trusted.rs
deleted file mode 100644
index f15c075e..00000000
--- a/vendor/iri-string/src/parser/trusted.rs
+++ /dev/null
@@ -1,476 +0,0 @@
-//! Fast parsers for trusted (already validated) input.
-//!
-//! Using this in wrong way will lead to unexpected wrong result.
-
-pub(crate) mod authority;
-
-use core::cmp::Ordering;
-use core::num::NonZeroUsize;
-
-use crate::components::{RiReferenceComponents, Splitter};
-use crate::format::eq_str_display;
-use crate::normalize::{is_pct_case_normalized, NormalizedAsciiOnlyHost, NormalizednessCheckMode};
-use crate::parser::str::{find_split2, find_split3, find_split4_hole, find_split_hole};
-use crate::spec::Spec;
-use crate::types::RiReferenceStr;
-
-/// Eats a `scheme` and a following colon, and returns the rest and the scheme.
-///
-/// Returns `(rest, scheme)`.
-///
-/// This should be called at the head of an absolute IRIs/URIs.
-#[must_use]
-fn scheme_colon(i: &str) -> (&str, &str) {
- let (scheme, rest) =
- find_split_hole(i, b':').expect("[precondition] absolute IRIs must have `scheme` part");
- (rest, scheme)
-}
-
-/// Eats a `scheme` and a following colon if available, and returns the rest and the scheme.
-///
-/// This should be called at the head of an `IRI-reference` or similar.
-#[must_use]
-fn scheme_colon_opt(i: &str) -> (&str, Option<&str>) {
- match find_split4_hole(i, b':', b'/', b'?', b'#') {
- Some((scheme, b':', rest)) => (rest, Some(scheme)),
- _ => (i, None),
- }
-}
-
-/// Eats double slash and the following authority if available, and returns the authority.
-///
-/// This should be called at the head of an `IRI-reference`, or at the result of `scheme_colon`.
-#[must_use]
-fn slash_slash_authority_opt(i: &str) -> (&str, Option<&str>) {
- let s = match i.strip_prefix("//") {
- Some(rest) => rest,
- None => return (i, None),
- };
- // `i` might match `path-abempty` (which can start with `//`), but it is not
- // allowed as `relative-part`, so no need to care `path-abempty` rule here.
- // A slash, question mark, and hash character won't appear in `authority`.
- match find_split3(s, b'/', b'?', b'#') {
- Some((authority, rest)) => (rest, Some(authority)),
- None => ("", Some(s)),
- }
-}
-
-/// Eats a string until the query, and returns that part (excluding `?` for the query).
-#[must_use]
-fn until_query(i: &str) -> (&str, &str) {
- // `?` won't appear before the query part.
- match find_split2(i, b'?', b'#') {
- Some((before_query, rest)) => (rest, before_query),
- None => ("", i),
- }
-}
-
-/// Decomposes query and fragment, if available.
-///
-/// The string must starts with `?`, or `#`, or be empty.
-#[must_use]
-fn decompose_query_and_fragment(i: &str) -> (Option<&str>, Option<&str>) {
- match i.as_bytes().first().copied() {
- None => (None, None),
- Some(b'?') => {
- let rest = &i[1..];
- match find_split_hole(rest, b'#') {
- Some((query, fragment)) => (Some(query), Some(fragment)),
- None => (Some(rest), None),
- }
- }
- Some(c) => {
- debug_assert_eq!(c, b'#');
- (None, Some(&i[1..]))
- }
- }
-}
-
-/// Decomposes the given valid `IRI-reference`.
-#[must_use]
-pub(crate) fn decompose_iri_reference<S: Spec>(
- i: &RiReferenceStr<S>,
-) -> RiReferenceComponents<'_, S> {
- /// Inner function to avoid unnecessary monomorphizations on `S`.
- fn decompose(i: &str) -> Splitter {
- let len = i.len();
-
- let (i, scheme_end) = {
- let (i, scheme) = scheme_colon_opt(i);
- let end = scheme.and_then(|s| NonZeroUsize::new(s.len()));
- (i, end)
- };
- let (i, authority_end) = {
- // 2: "//".len()
- let start = len - i.len() + 2;
- // `authority` does not contain the two slashes of `://'.
- let (i, authority) = slash_slash_authority_opt(i);
- let end = authority.and_then(|s| NonZeroUsize::new(start + s.len()));
- (i, end)
- };
- let (i, _path) = until_query(i);
-
- let (query_start, fragment_start) = {
- // This could theoretically be zero if `len` is `usize::MAX` and
- // `i` has neither a query nor a fragment. However, this is
- // practically impossible.
- let after_first_prefix = NonZeroUsize::new((len - i.len()).wrapping_add(1));
-
- let (query, fragment) = decompose_query_and_fragment(i);
- match (query.is_some(), fragment) {
- (true, Some(fragment)) => {
- (after_first_prefix, NonZeroUsize::new(len - fragment.len()))
- }
- (true, None) => (after_first_prefix, None),
- (false, Some(_fragment)) => (None, after_first_prefix),
- (false, None) => (None, None),
- }
- };
-
- Splitter::new(scheme_end, authority_end, query_start, fragment_start)
- }
-
- RiReferenceComponents {
- iri: i,
- splitter: decompose(i.as_str()),
- }
-}
-
-/// Extracts `scheme` part from an IRI reference.
-///
-/// # Precondition
-///
-/// The given string must be a valid IRI reference.
-#[inline]
-#[must_use]
-pub(crate) fn extract_scheme(i: &str) -> Option<&str> {
- scheme_colon_opt(i).1
-}
-
-/// Extracts `scheme` part from an absolute IRI.
-///
-/// # Precondition
-///
-/// The given string must be a valid absolute IRI.
-#[inline]
-#[must_use]
-pub(crate) fn extract_scheme_absolute(i: &str) -> &str {
- scheme_colon(i).1
-}
-
-/// Extracts `authority` part from an IRI reference.
-///
-/// # Precondition
-///
-/// The given string must be a valid IRI reference.
-#[inline]
-#[must_use]
-pub(crate) fn extract_authority(i: &str) -> Option<&str> {
- let (i, _scheme) = scheme_colon_opt(i);
- slash_slash_authority_opt(i).1
-}
-
-/// Extracts `authority` part from an absolute IRI.
-///
-/// # Precondition
-///
-/// The given string must be a valid absolute IRI.
-#[inline]
-#[must_use]
-pub(crate) fn extract_authority_absolute(i: &str) -> Option<&str> {
- let (i, _scheme) = scheme_colon(i);
- slash_slash_authority_opt(i).1
-}
-
-/// Extracts `authority` part from a relative IRI.
-///
-/// # Precondition
-///
-/// The given string must be a valid relative IRI.
-#[inline]
-#[must_use]
-pub(crate) fn extract_authority_relative(i: &str) -> Option<&str> {
- slash_slash_authority_opt(i).1
-}
-
-/// Extracts `path` part from an IRI reference.
-///
-/// # Precondition
-///
-/// The given string must be a valid IRI reference.
-#[inline]
-#[must_use]
-pub(crate) fn extract_path(i: &str) -> &str {
- let (i, _scheme) = scheme_colon_opt(i);
- let (i, _authority) = slash_slash_authority_opt(i);
- until_query(i).1
-}
-
-/// Extracts `path` part from an absolute IRI.
-///
-/// # Precondition
-///
-/// The given string must be a valid absolute IRI.
-#[inline]
-#[must_use]
-pub(crate) fn extract_path_absolute(i: &str) -> &str {
- let (i, _scheme) = scheme_colon(i);
- let (i, _authority) = slash_slash_authority_opt(i);
- until_query(i).1
-}
-
-/// Extracts `path` part from a relative IRI.
-///
-/// # Precondition
-///
-/// The given string must be a valid relative IRI.
-#[inline]
-#[must_use]
-pub(crate) fn extract_path_relative(i: &str) -> &str {
- let (i, _authority) = slash_slash_authority_opt(i);
- until_query(i).1
-}
-
-/// Extracts `query` part from an IRI reference.
-///
-/// # Precondition
-///
-/// The given string must be a valid IRI reference.
-#[inline]
-#[must_use]
-pub(crate) fn extract_query(i: &str) -> Option<&str> {
- let (i, _before_query) = until_query(i);
- decompose_query_and_fragment(i).0
-}
-
-/// Extracts `query` part from an `absolute-IRI` string.
-///
-/// # Precondition
-///
-/// The given string must be a valid `absolute-IRI` string.
-#[must_use]
-pub(crate) fn extract_query_absolute_iri(i: &str) -> Option<&str> {
- let (i, _before_query) = until_query(i);
- if i.is_empty() {
- None
- } else {
- debug_assert_eq!(
- i.as_bytes().first(),
- Some(&b'?'),
- "`absolute-IRI` string must not have `fragment part"
- );
- Some(&i[1..])
- }
-}
-
-/// Splits an IRI string into the prefix and the fragment part.
-///
-/// A leading `#` character is truncated if the fragment part exists.
-///
-/// # Precondition
-///
-/// The given string must be a valid IRI reference.
-#[inline]
-#[must_use]
-pub(crate) fn split_fragment(iri: &str) -> (&str, Option<&str>) {
- // It is completely OK to find the first `#` character from valid IRI to get fragment part,
- // because the spec says that there are no `#` characters before the fragment part.
- //
- // > ```
- // > scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
- // > ```
- // >
- // > --- [RFC 3986, section 3.1. Scheme](https://tools.ietf.org/html/rfc3986#section-3.1)
- //
- // > The authority component is preceded by a double slash ("//") and is terminated by the
- // > next slash ("/"), question mark ("?"), or number sign ("#") character, or by the end
- // > of the URI.
- // >
- // > --- [RFC 3986, section 3.2. Authority](https://tools.ietf.org/html/rfc3986#section-3.2)
- //
- // > The path is terminated by the first question mark ("?") or number sign ("#")
- // > character, or by the end of the URI.
- // >
- // > --- [RFC 3986, section 3.3. Path](https://tools.ietf.org/html/rfc3986#section-3.3)
- //
- // > The query component is indicated by the first question mark ("?") character and
- // > terminated by a number sign ("#") character or by the end of the URI.
- // >
- // > --- [RFC 3986, section 3.4. Query](https://tools.ietf.org/html/rfc3986#section-3.4)
- match find_split_hole(iri, b'#') {
- Some((prefix, fragment)) => (prefix, Some(fragment)),
- None => (iri, None),
- }
-}
-
-/// Returns the fragment part of the given IRI.
-///
-/// A leading `#` character of the fragment is truncated.
-#[inline]
-#[must_use]
-pub(crate) fn extract_fragment(iri: &str) -> Option<&str> {
- split_fragment(iri).1
-}
-
-/// Returns `Ok(_)` if the string is normalized.
-///
-/// If this function returns `true`, normalization input and output will be identical.
-///
-/// In this function, "normalized" means that any of the normalization below
-/// won't change the input on normalization:
-///
-/// * syntax-based normalization,
-/// * case normalization,
-/// * percent-encoding normalization, and
-/// * path segment normalizaiton.
-///
-/// Note that scheme-based normalization is not considered.
-#[must_use]
-pub(crate) fn is_normalized<S: Spec>(i: &str, mode: NormalizednessCheckMode) -> bool {
- let (i, scheme) = scheme_colon(i);
- let (after_authority, authority) = slash_slash_authority_opt(i);
- let (_after_path, path) = until_query(after_authority);
-
- // Syntax-based normalization: uppercase chars in `scheme` should be
- // converted to lowercase.
- if scheme.bytes().any(|b| b.is_ascii_uppercase()) {
- return false;
- }
-
- // Case normalization: ASCII alphabets in US-ASCII only `host` should be
- // normalized to lowercase.
- // Case normalization: ASCII alphabets in percent-encoding triplet should be
- // normalized to uppercase.
- // Percent-encoding normalization: unresreved characters should be decoded
- // in `userinfo`, `host`, `path`, `query`, and `fragments`.
- // Path segment normalization: the path should not have dot segments (`.`
- // and/or `..`).
- //
- // Note that `authority` can have percent-encoded `userinfo`.
- if let Some(authority) = authority {
- let authority_components = authority::decompose_authority(authority);
-
- // Check `host`.
- let host = authority_components.host();
- let host_is_normalized = if is_ascii_only_host(host) {
- eq_str_display(host, &NormalizedAsciiOnlyHost::new(host))
- } else {
- // If the host is not ASCII-only, conversion to lowercase is not performed.
- is_pct_case_normalized::<S>(host)
- };
- if !host_is_normalized {
- return false;
- }
-
- // Check pencent encodings in `userinfo`.
- if let Some(userinfo) = authority_components.userinfo() {
- if !is_pct_case_normalized::<S>(userinfo) {
- return false;
- }
- }
- }
-
- // Check `path`.
- //
- // Syntax-based normalization: Dot segments might be removed.
- // Note that we don't have to care `%2e` and `%2E` since `.` is unreserved
- // and they will be decoded if not normalized.
- // Also note that WHATWG serialization will use `/.//` as a path prefix if
- // the path is absolute and won't modify the path if the path is relative.
- //
- // Percent-encoding normalization: unresreved characters should be decoded
- // in `path`, `query`, and `fragments`.
- let path_span_no_dot_segments = if authority.is_some() {
- Some(path)
- } else {
- match mode {
- NormalizednessCheckMode::Default => Some(path.strip_prefix("/.//").unwrap_or(path)),
- NormalizednessCheckMode::Rfc3986 => Some(path),
- NormalizednessCheckMode::PreserveAuthoritylessRelativePath => {
- if path.starts_with('/') {
- // Absolute.
- Some(path.strip_prefix("/.//").unwrap_or(path))
- } else {
- // Relative. Treat the path as "opaque". No span to check.
- None
- }
- }
- }
- };
- if let Some(path_span_no_dot_segments) = path_span_no_dot_segments {
- if path_span_no_dot_segments
- .split('/')
- .any(|segment| matches!(segment, "." | ".."))
- {
- return false;
- }
- }
- is_pct_case_normalized::<S>(after_authority)
-}
-
-/// Decodes two hexdigits into a byte.
-///
-/// # Preconditions
-///
-/// The parameters `upper` and `lower` should be an ASCII hexadecimal digit.
-#[must_use]
-pub(super) fn hexdigits_to_byte([upper, lower]: [u8; 2]) -> u8 {
- let i_upper = match (upper & 0xf0).cmp(&0x40) {
- Ordering::Less => upper - b'0',
- Ordering::Equal => upper - (b'A' - 10),
- Ordering::Greater => upper - (b'a' - 10),
- };
- let i_lower = match (lower & 0xf0).cmp(&0x40) {
- Ordering::Less => lower - b'0',
- Ordering::Equal => lower - (b'A' - 10),
- Ordering::Greater => lower - (b'a' - 10),
- };
- (i_upper << 4) + i_lower
-}
-
-/// Converts the first two hexdigit bytes in the buffer into a byte.
-///
-/// # Panics
-///
-/// Panics if the string does not start with two hexdigits.
-#[must_use]
-pub(crate) fn take_xdigits2(s: &str) -> (u8, &str) {
- let mut bytes = s.bytes();
- let upper_xdigit = bytes
- .next()
- .expect("[validity] at least two bytes should follow the `%` in a valid IRI reference");
- let lower_xdigit = bytes
- .next()
- .expect("[validity] at least two bytes should follow the `%` in a valid IRI reference");
- let v = hexdigits_to_byte([upper_xdigit, lower_xdigit]);
- (v, &s[2..])
-}
-
-/// Returns true if the given `host`/`ihost` string consists of only US-ASCII characters.
-///
-/// # Precondition
-///
-/// The given string should be valid `host` or `host ":" port` string.
-#[must_use]
-pub(crate) fn is_ascii_only_host(mut host: &str) -> bool {
- while let Some((i, c)) = host
- .char_indices()
- .find(|(_i, c)| !c.is_ascii() || *c == '%')
- {
- if c != '%' {
- // Non-ASCII character found.
- debug_assert!(!c.is_ascii());
- return false;
- }
- // Percent-encoded character found.
- let after_pct = &host[(i + 1)..];
- let (byte, rest) = take_xdigits2(after_pct);
- if !byte.is_ascii() {
- return false;
- }
- host = rest;
- }
-
- // Neither non-ASCII characters nor percent-encoded characters found.
- true
-}
diff --git a/vendor/iri-string/src/parser/trusted/authority.rs b/vendor/iri-string/src/parser/trusted/authority.rs
deleted file mode 100644
index 83e41298..00000000
--- a/vendor/iri-string/src/parser/trusted/authority.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-//! Parsers for trusted `authority` string.
-
-use crate::components::AuthorityComponents;
-use crate::parser::str::{find_split_hole, rfind_split2};
-
-/// Decomposes the authority into `(userinfo, host, port)`.
-///
-/// The leading `:` is truncated.
-///
-/// # Precondition
-///
-/// The given string must be a valid IRI reference.
-#[inline]
-#[must_use]
-pub(crate) fn decompose_authority(authority: &str) -> AuthorityComponents<'_> {
- let i = authority;
- let (i, host_start) = match find_split_hole(i, b'@') {
- Some((userinfo, rest)) => (rest, userinfo.len() + 1),
- None => (authority, 0),
- };
- let colon_port_len = match rfind_split2(i, b':', b']') {
- Some((_, suffix)) if suffix.starts_with(':') => suffix.len(),
- _ => 0,
- };
- let host_end = authority.len() - colon_port_len;
-
- AuthorityComponents {
- authority,
- host_start,
- host_end,
- }
-}
diff --git a/vendor/iri-string/src/parser/validate.rs b/vendor/iri-string/src/parser/validate.rs
deleted file mode 100644
index 59625394..00000000
--- a/vendor/iri-string/src/parser/validate.rs
+++ /dev/null
@@ -1,225 +0,0 @@
-//! Validating parsers for non-trusted (possibly invalid) input.
-
-mod authority;
-mod path;
-
-use crate::parser::char;
-use crate::parser::str::{
- find_split, find_split2_hole, find_split_hole, satisfy_chars_with_pct_encoded,
-};
-use crate::spec::Spec;
-use crate::validate::Error;
-
-use self::authority::validate_authority;
-pub(crate) use self::authority::{validate_host, validate_userinfo};
-pub(crate) use self::path::validate_path;
-use self::path::{
- validate_path_abempty, validate_path_absolute_authority_absent,
- validate_path_relative_authority_absent,
-};
-
-/// Returns `Ok(_)` if the string matches `scheme`.
-pub(crate) fn validate_scheme(i: &str) -> Result<(), Error> {
- debug_assert!(!i.is_empty());
- let bytes = i.as_bytes();
- if bytes[0].is_ascii_alphabetic()
- && bytes[1..]
- .iter()
- .all(|&b| b.is_ascii() && char::is_ascii_scheme_continue(b))
- {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
-
-/// Returns `Ok(_)` if the string matches `query` or `iquery`.
-pub(crate) fn validate_query<S: Spec>(i: &str) -> Result<(), Error> {
- let is_valid =
- satisfy_chars_with_pct_encoded(i, char::is_ascii_frag_query, char::is_nonascii_query::<S>);
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
-
-/// Returns `Ok(_)` if the string matches `authority path-abempty` rule sequence.
-fn validate_authority_path_abempty<S: Spec>(i: &str) -> Result<(), Error> {
- let (maybe_authority, maybe_path) = match find_split(i, b'/') {
- Some(v) => v,
- None => (i, ""),
- };
- validate_authority::<S>(maybe_authority)?;
- validate_path_abempty::<S>(maybe_path)
-}
-
-/// Returns `Ok(_)` if the string matches `URI`/`IRI` rules.
-#[inline]
-pub(crate) fn validate_uri<S: Spec>(i: &str) -> Result<(), Error> {
- validate_uri_reference_common::<S>(i, UriReferenceRule::Absolute)
-}
-
-/// Returns `Ok(_)` if the string matches `URI-reference`/`IRI-reference` rules.
-#[inline]
-pub(crate) fn validate_uri_reference<S: Spec>(i: &str) -> Result<(), Error> {
- validate_uri_reference_common::<S>(i, UriReferenceRule::Any)
-}
-
-/// Returns `Ok(_)` if the string matches `absolute-URI`/`absolute-IRI` rules.
-#[inline]
-pub(crate) fn validate_absolute_uri<S: Spec>(i: &str) -> Result<(), Error> {
- validate_uri_reference_common::<S>(i, UriReferenceRule::AbsoluteWithoutFragment)
-}
-
-/// Syntax rule for URI/IRI references.
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-enum UriReferenceRule {
- /// `URI` and `IRI`.
- ///
- /// This can have a fragment.
- Absolute,
- /// `absolute-URI` and `absolute-IRI`.
- ///
- /// This cannot have a fragment.
- AbsoluteWithoutFragment,
- /// `URI-reference` and `IRI-reference`.
- ///
- /// This can be relative.
- Any,
-}
-
-impl UriReferenceRule {
- /// Returns `true` is the relative reference is allowed.
- #[inline]
- #[must_use]
- fn is_relative_allowed(self) -> bool {
- self == Self::Any
- }
-
- /// Returns `true` is the fragment part is allowed.
- #[inline]
- #[must_use]
- fn is_fragment_allowed(self) -> bool {
- matches!(self, Self::Absolute | Self::Any)
- }
-}
-
-/// Returns `Ok(_)` if the string matches `URI-reference`/`IRI-reference` rules.
-fn validate_uri_reference_common<S: Spec>(
- i: &str,
- ref_rule: UriReferenceRule,
-) -> Result<(), Error> {
- // Validate `scheme ":"`.
- let (i, _scheme) = match find_split_hole(i, b':') {
- None => {
- if ref_rule.is_relative_allowed() {
- return validate_relative_ref::<S>(i);
- } else {
- return Err(Error::new());
- }
- }
- Some(("", _)) => return Err(Error::new()),
- Some((maybe_scheme, rest)) => {
- if validate_scheme(maybe_scheme).is_err() {
- // The string before the first colon is not a scheme.
- // Falling back to `relative-ref` parsing.
- if ref_rule.is_relative_allowed() {
- return validate_relative_ref::<S>(i);
- } else {
- return Err(Error::new());
- }
- }
- (rest, maybe_scheme)
- }
- };
-
- // Validate `hier-part`.
- let after_path = match i.strip_prefix("//") {
- Some(i) => {
- let (maybe_authority_path, after_path) = match find_split2_hole(i, b'?', b'#') {
- Some((maybe_authority_path, c, rest)) => (maybe_authority_path, Some((c, rest))),
- None => (i, None),
- };
- validate_authority_path_abempty::<S>(maybe_authority_path)?;
- after_path
- }
- None => {
- let (maybe_path, after_path) = match find_split2_hole(i, b'?', b'#') {
- Some((maybe_path, c, rest)) => (maybe_path, Some((c, rest))),
- None => (i, None),
- };
- // Authority is absent.
- validate_path_absolute_authority_absent::<S>(maybe_path)?;
- after_path
- }
- };
-
- // Validate `[ "?" query ] [ "#" fragment ]`.
- if let Some((first, rest)) = after_path {
- validate_after_path::<S>(first, rest, ref_rule.is_fragment_allowed())?;
- }
- Ok(())
-}
-
-/// Returns `Ok(_)` if the string matches `relative-ref`/`irelative-ref` rules.
-pub(crate) fn validate_relative_ref<S: Spec>(i: &str) -> Result<(), Error> {
- // Validate `relative-part`.
- let after_path = match i.strip_prefix("//") {
- Some(i) => {
- let (maybe_authority_path, after_path) = match find_split2_hole(i, b'?', b'#') {
- Some((maybe_authority_path, c, rest)) => (maybe_authority_path, Some((c, rest))),
- None => (i, None),
- };
- validate_authority_path_abempty::<S>(maybe_authority_path)?;
- after_path
- }
- None => {
- let (maybe_path, after_path) = match find_split2_hole(i, b'?', b'#') {
- Some((maybe_path, c, rest)) => (maybe_path, Some((c, rest))),
- None => (i, None),
- };
- // Authority is absent.
- validate_path_relative_authority_absent::<S>(maybe_path)?;
- after_path
- }
- };
-
- // Validate `[ "?" query ] [ "#" fragment ]`.
- if let Some((first, rest)) = after_path {
- validate_after_path::<S>(first, rest, true)?;
- }
- Ok(())
-}
-
-/// Returns `Ok(_)` if the string matches `[ "?" query ] [ "#" fragment ]` (or IRI version).
-fn validate_after_path<S: Spec>(first: u8, rest: &str, accept_fragment: bool) -> Result<(), Error> {
- let (maybe_query, maybe_fragment) = if first == b'?' {
- match find_split_hole(rest, b'#') {
- Some(v) => v,
- None => (rest, ""),
- }
- } else {
- debug_assert_eq!(first, b'#');
- ("", rest)
- };
- validate_query::<S>(maybe_query)?;
- if !accept_fragment && !maybe_fragment.is_empty() {
- return Err(Error::new());
- }
- validate_fragment::<S>(maybe_fragment)
-}
-
-/// Returns `Ok(_)` if the string matches `fragment`/`ifragment` rules.
-pub(crate) fn validate_fragment<S: Spec>(i: &str) -> Result<(), Error> {
- let is_valid = satisfy_chars_with_pct_encoded(
- i,
- char::is_ascii_frag_query,
- char::is_nonascii_fragment::<S>,
- );
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
diff --git a/vendor/iri-string/src/parser/validate/authority.rs b/vendor/iri-string/src/parser/validate/authority.rs
deleted file mode 100644
index fb41085e..00000000
--- a/vendor/iri-string/src/parser/validate/authority.rs
+++ /dev/null
@@ -1,296 +0,0 @@
-//! Parsers for authority.
-
-use core::mem;
-
-use crate::parser::char;
-use crate::parser::str::{
- find_split_hole, get_wrapped_inner, rfind_split_hole, satisfy_chars_with_pct_encoded,
- strip_ascii_char_prefix,
-};
-use crate::spec::Spec;
-use crate::validate::Error;
-
-/// Returns `Ok(_)` if the string matches `userinfo` or `iuserinfo`.
-pub(crate) fn validate_userinfo<S: Spec>(i: &str) -> Result<(), Error> {
- let is_valid = satisfy_chars_with_pct_encoded(
- i,
- char::is_ascii_userinfo_ipvfutureaddr,
- char::is_nonascii_userinfo::<S>,
- );
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
-
-/// Returns `true` if the string matches `dec-octet`.
-///
-/// In other words, this tests whether the string is decimal "0" to "255".
-#[must_use]
-fn is_dec_octet(i: &str) -> bool {
- matches!(
- i.as_bytes(),
- [b'0'..=b'9']
- | [b'1'..=b'9', b'0'..=b'9']
- | [b'1', b'0'..=b'9', b'0'..=b'9']
- | [b'2', b'0'..=b'4', b'0'..=b'9']
- | [b'2', b'5', b'0'..=b'5']
- )
-}
-
-/// Returns `Ok(_)` if the string matches `IPv4address`.
-fn validate_ipv4address(i: &str) -> Result<(), Error> {
- let (first, rest) = find_split_hole(i, b'.').ok_or_else(Error::new)?;
- if !is_dec_octet(first) {
- return Err(Error::new());
- }
- let (second, rest) = find_split_hole(rest, b'.').ok_or_else(Error::new)?;
- if !is_dec_octet(second) {
- return Err(Error::new());
- }
- let (third, fourth) = find_split_hole(rest, b'.').ok_or_else(Error::new)?;
- if is_dec_octet(third) && is_dec_octet(fourth) {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
-
-/// A part of IPv6 addr.
-#[derive(Clone, Copy)]
-enum V6AddrPart {
- /// `[0-9a-fA-F]{1,4}::`.
- H16Omit,
- /// `[0-9a-fA-F]{1,4}:`.
- H16Cont,
- /// `[0-9a-fA-F]{1,4}`.
- H16End,
- /// IPv4 address.
- V4,
- /// `::`.
- Omit,
-}
-
-/// Splits the IPv6 address string into the next component and the rest substring.
-fn split_v6_addr_part(i: &str) -> Result<(&str, V6AddrPart), Error> {
- debug_assert!(!i.is_empty());
- match find_split_hole(i, b':') {
- Some((prefix, rest)) => {
- if prefix.len() >= 5 {
- return Err(Error::new());
- }
-
- if prefix.is_empty() {
- return match strip_ascii_char_prefix(rest, b':') {
- Some(rest) => Ok((rest, V6AddrPart::Omit)),
- None => Err(Error::new()),
- };
- }
-
- // Should be `h16`.
- debug_assert!((1..=4).contains(&prefix.len()));
- if !prefix.bytes().all(|b| b.is_ascii_hexdigit()) {
- return Err(Error::new());
- }
- match strip_ascii_char_prefix(rest, b':') {
- Some(rest) => Ok((rest, V6AddrPart::H16Omit)),
- None => Ok((rest, V6AddrPart::H16Cont)),
- }
- }
- None => {
- if i.len() >= 5 {
- // Possibly `IPv4address`.
- validate_ipv4address(i)?;
- return Ok(("", V6AddrPart::V4));
- }
- if i.bytes().all(|b| b.is_ascii_hexdigit()) {
- Ok(("", V6AddrPart::H16End))
- } else {
- Err(Error::new())
- }
- }
- }
-}
-
-/// Returns `Ok(_)` if the string matches `IPv6address`.
-fn validate_ipv6address(mut i: &str) -> Result<(), Error> {
- let mut h16_count = 0;
- let mut is_omitted = false;
- while !i.is_empty() {
- let (rest, part) = split_v6_addr_part(i)?;
- match part {
- V6AddrPart::H16Omit => {
- h16_count += 1;
- if mem::replace(&mut is_omitted, true) {
- // Omitted twice.
- return Err(Error::new());
- }
- }
- V6AddrPart::H16Cont => {
- h16_count += 1;
- if rest.is_empty() {
- // `H16Cont` cannot be the last part of an IPv6 address.
- return Err(Error::new());
- }
- }
- V6AddrPart::H16End => {
- h16_count += 1;
- break;
- }
- V6AddrPart::V4 => {
- debug_assert!(rest.is_empty());
- h16_count += 2;
- break;
- }
- V6AddrPart::Omit => {
- if mem::replace(&mut is_omitted, true) {
- // Omitted twice.
- return Err(Error::new());
- }
- }
- }
- if h16_count > 8 {
- return Err(Error::new());
- }
- i = rest;
- }
- let is_valid = if is_omitted {
- h16_count < 8
- } else {
- h16_count == 8
- };
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
-
-/// Returns `Ok(_)` if the string matches `authority` or `iauthority`.
-pub(super) fn validate_authority<S: Spec>(i: &str) -> Result<(), Error> {
- // Strip and validate `userinfo`.
- let (i, _userinfo) = match find_split_hole(i, b'@') {
- Some((maybe_userinfo, i)) => {
- validate_userinfo::<S>(maybe_userinfo)?;
- (i, Some(maybe_userinfo))
- }
- None => (i, None),
- };
- // `host` can contain colons, but `port` cannot.
- // Strip and validate `port`.
- let (maybe_host, _port) = match rfind_split_hole(i, b':') {
- Some((maybe_host, maybe_port)) => {
- if maybe_port.bytes().all(|b| b.is_ascii_digit()) {
- (maybe_host, Some(maybe_port))
- } else {
- (i, None)
- }
- }
- None => (i, None),
- };
- // Validate `host`.
- validate_host::<S>(maybe_host)
-}
-
-/// Validates `host`.
-pub(crate) fn validate_host<S: Spec>(i: &str) -> Result<(), Error> {
- match get_wrapped_inner(i, b'[', b']') {
- Some(maybe_addr) => {
- // `IP-literal`.
- // Note that `v` here is case insensitive. See RFC 3987 section 3.2.2.
- if let Some(maybe_addr_rest) = strip_ascii_char_prefix(maybe_addr, b'v')
- .or_else(|| strip_ascii_char_prefix(maybe_addr, b'V'))
- {
- // `IPvFuture`.
- let (maybe_ver, maybe_addr) =
- find_split_hole(maybe_addr_rest, b'.').ok_or_else(Error::new)?;
- // Validate version.
- if maybe_ver.is_empty() || !maybe_ver.bytes().all(|b| b.is_ascii_hexdigit()) {
- return Err(Error::new());
- }
- // Validate address.
- if !maybe_addr.is_empty()
- && maybe_addr.is_ascii()
- && maybe_addr
- .bytes()
- .all(char::is_ascii_userinfo_ipvfutureaddr)
- {
- Ok(())
- } else {
- Err(Error::new())
- }
- } else {
- // `IPv6address`.
- validate_ipv6address(maybe_addr)
- }
- }
- None => {
- // `IPv4address` or `reg-name`. No need to distinguish them here.
- let is_valid = satisfy_chars_with_pct_encoded(
- i,
- char::is_ascii_regname,
- char::is_nonascii_regname::<S>,
- );
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
- }
- }
-}
-
-#[cfg(test)]
-#[cfg(feature = "alloc")]
-mod tests {
- use super::*;
-
- use alloc::format;
-
- macro_rules! assert_validate {
- ($parser:expr, $($input:expr),* $(,)?) => {{
- $({
- let input = $input;
- let input: &str = input.as_ref();
- assert!($parser(input).is_ok(), "input={:?}", input);
- })*
- }};
- }
-
- #[test]
- fn test_ipv6address() {
- use core::cmp::Ordering;
-
- assert_validate!(validate_ipv6address, "a:bB:cCc:dDdD:e:F:a:B");
- assert_validate!(validate_ipv6address, "1:1:1:1:1:1:1:1");
- assert_validate!(validate_ipv6address, "1:1:1:1:1:1:1.1.1.1");
- assert_validate!(validate_ipv6address, "2001:db8::7");
-
- // Generate IPv6 addresses with `::`.
- let make_sub = |n: usize| {
- let mut s = "1:".repeat(n);
- s.pop();
- s
- };
- for len_pref in 0..=7 {
- let prefix = make_sub(len_pref);
- for len_suf in 1..=(7 - len_pref) {
- assert_validate!(
- validate_ipv6address,
- &format!("{}::{}", prefix, make_sub(len_suf))
- );
- match len_suf.cmp(&2) {
- Ordering::Greater => assert_validate!(
- validate_ipv6address,
- &format!("{}::{}:1.1.1.1", prefix, make_sub(len_suf - 2))
- ),
- Ordering::Equal => {
- assert_validate!(validate_ipv6address, &format!("{}::1.1.1.1", prefix))
- }
- Ordering::Less => {}
- }
- }
- }
- }
-}
diff --git a/vendor/iri-string/src/parser/validate/path.rs b/vendor/iri-string/src/parser/validate/path.rs
deleted file mode 100644
index 1b09c84b..00000000
--- a/vendor/iri-string/src/parser/validate/path.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-//! Parsers for path.
-
-use crate::parser::char;
-use crate::parser::str::{find_split2_hole, satisfy_chars_with_pct_encoded};
-use crate::spec::Spec;
-use crate::validate::Error;
-
-/// Returns `Ok(_)` if the string matches `path-abempty` or `ipath-abempty`.
-pub(super) fn validate_path_abempty<S: Spec>(i: &str) -> Result<(), Error> {
- if i.is_empty() {
- return Ok(());
- }
- let i = match i.strip_prefix('/') {
- Some(rest) => rest,
- None => return Err(Error::new()),
- };
- let is_valid = satisfy_chars_with_pct_encoded(
- i,
- char::is_ascii_pchar_slash,
- S::is_nonascii_char_unreserved,
- );
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
-
-/// Returns `Ok(_)` if the string matches `hier-part` or `ihier-part` modulo
-/// `"//" authority path-abempty`.
-pub(super) fn validate_path_absolute_authority_absent<S: Spec>(i: &str) -> Result<(), Error> {
- if i.is_empty() {
- // `path-empty`.
- return Ok(());
- }
- if i.starts_with("//") {
- unreachable!("this case should be handled by the caller");
- }
- let is_valid = satisfy_chars_with_pct_encoded(
- i,
- char::is_ascii_pchar_slash,
- S::is_nonascii_char_unreserved,
- );
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
-
-/// Returns `Ok(_)` if the string matches `relative-part` or `irelative-part` modulo
-/// `"//" authority path-abempty`.
-pub(super) fn validate_path_relative_authority_absent<S: Spec>(i: &str) -> Result<(), Error> {
- if i.starts_with("//") {
- unreachable!("this case should be handled by the caller");
- }
- let is_valid = match find_split2_hole(i, b'/', b':') {
- Some((_, b'/', _)) | None => satisfy_chars_with_pct_encoded(
- i,
- char::is_ascii_pchar_slash,
- S::is_nonascii_char_unreserved,
- ),
- Some((_, c, _)) => {
- debug_assert_eq!(c, b':');
- // `foo:bar`-style. This does not match `path-noscheme`.
- return Err(Error::new());
- }
- };
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
-
-/// Returns `Ok(_)` if the string matches `path`/`ipath` rules.
-pub(crate) fn validate_path<S: Spec>(i: &str) -> Result<(), Error> {
- if i.starts_with("//") {
- return Err(Error::new());
- }
- let is_valid = satisfy_chars_with_pct_encoded(
- i,
- char::is_ascii_pchar_slash,
- S::is_nonascii_char_unreserved,
- );
- if is_valid {
- Ok(())
- } else {
- Err(Error::new())
- }
-}
diff --git a/vendor/iri-string/src/percent_encode.rs b/vendor/iri-string/src/percent_encode.rs
deleted file mode 100644
index b5997a03..00000000
--- a/vendor/iri-string/src/percent_encode.rs
+++ /dev/null
@@ -1,378 +0,0 @@
-//! Percent encoding.
-
-use core::fmt::{self, Write as _};
-use core::marker::PhantomData;
-
-use crate::parser::char;
-use crate::spec::{IriSpec, Spec, UriSpec};
-
-/// A proxy to percent-encode a string as a part of URI.
-pub type PercentEncodedForUri<T> = PercentEncoded<T, UriSpec>;
-
-/// A proxy to percent-encode a string as a part of IRI.
-pub type PercentEncodedForIri<T> = PercentEncoded<T, IriSpec>;
-
-/// Context for percent encoding.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-#[non_exhaustive]
-enum Context {
- /// Encode the string as a reg-name (usually called as "hostname").
- RegName,
- /// Encode the string as a user name or a password (inside the `userinfo` component).
- UserOrPassword,
- /// Encode the string as a path segment.
- ///
- /// A slash (`/`) will be encoded to `%2F`.
- PathSegment,
- /// Encode the string as path segments joined with `/`.
- ///
- /// A slash (`/`) will be used as is.
- Path,
- /// Encode the string as a query string (without the `?` prefix).
- Query,
- /// Encode the string as a fragment string (without the `#` prefix).
- Fragment,
- /// Encode all characters except for `unreserved` characters.
- Unreserve,
- /// Encode characters only if they cannot appear anywhere in an IRI reference.
- ///
- /// `%` character will be always encoded.
- Character,
-}
-
-/// A proxy to percent-encode a string.
-///
-/// Type aliases [`PercentEncodedForIri`] and [`PercentEncodedForUri`] are provided.
-/// You can use them to make the expression simpler, for example write
-/// `PercentEncodedForUri::from_path(foo)` instead of
-/// `PercentEncoded::<_, UriSpec>::from_path(foo)`.
-#[derive(Debug, Clone, Copy)]
-pub struct PercentEncoded<T, S> {
- /// Source string context.
- context: Context,
- /// Raw string before being encoded.
- raw: T,
- /// Spec.
- _spec: PhantomData<fn() -> S>,
-}
-
-impl<T: fmt::Display, S: Spec> PercentEncoded<T, S> {
- /// Creates an encoded string from a raw reg-name (i.e. hostname or domain).
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let raw = "alpha.\u{03B1}.example.com";
- /// let encoded = "alpha.%CE%B1.example.com";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::from_reg_name(raw).to_string(),
- /// encoded
- /// );
- /// # }
- /// ```
- pub fn from_reg_name(raw: T) -> Self {
- Self {
- context: Context::RegName,
- raw,
- _spec: PhantomData,
- }
- }
-
- /// Creates an encoded string from a raw user name (inside `userinfo` component).
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let raw = "user:\u{03B1}";
- /// // The first `:` will be interpreted as a delimiter, so colons will be escaped.
- /// let encoded = "user%3A%CE%B1";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::from_user(raw).to_string(),
- /// encoded
- /// );
- /// # }
- /// ```
- pub fn from_user(raw: T) -> Self {
- Self {
- context: Context::UserOrPassword,
- raw,
- _spec: PhantomData,
- }
- }
-
- /// Creates an encoded string from a raw user name (inside `userinfo` component).
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let raw = "password:\u{03B1}";
- /// // The first `:` will be interpreted as a delimiter, and the colon
- /// // inside the password will be the first one if the user name is empty,
- /// // so colons will be escaped.
- /// let encoded = "password%3A%CE%B1";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::from_password(raw).to_string(),
- /// encoded
- /// );
- /// # }
- /// ```
- pub fn from_password(raw: T) -> Self {
- Self {
- context: Context::UserOrPassword,
- raw,
- _spec: PhantomData,
- }
- }
-
- /// Creates an encoded string from a raw path segment.
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let raw = "alpha/\u{03B1}?#";
- /// // Note that `/` is encoded to `%2F`.
- /// let encoded = "alpha%2F%CE%B1%3F%23";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::from_path_segment(raw).to_string(),
- /// encoded
- /// );
- /// # }
- /// ```
- pub fn from_path_segment(raw: T) -> Self {
- Self {
- context: Context::PathSegment,
- raw,
- _spec: PhantomData,
- }
- }
-
- /// Creates an encoded string from a raw path.
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let raw = "alpha/\u{03B1}?#";
- /// // Note that `/` is NOT percent encoded.
- /// let encoded = "alpha/%CE%B1%3F%23";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::from_path(raw).to_string(),
- /// encoded
- /// );
- /// # }
- /// ```
- pub fn from_path(raw: T) -> Self {
- Self {
- context: Context::Path,
- raw,
- _spec: PhantomData,
- }
- }
-
- /// Creates an encoded string from a raw query.
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let raw = "alpha/\u{03B1}?#";
- /// let encoded = "alpha/%CE%B1?%23";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::from_query(raw).to_string(),
- /// encoded
- /// );
- /// # }
- /// ```
- pub fn from_query(raw: T) -> Self {
- Self {
- context: Context::Query,
- raw,
- _spec: PhantomData,
- }
- }
-
- /// Creates an encoded string from a raw fragment.
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let raw = "alpha/\u{03B1}?#";
- /// let encoded = "alpha/%CE%B1?%23";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::from_fragment(raw).to_string(),
- /// encoded
- /// );
- /// # }
- /// ```
- pub fn from_fragment(raw: T) -> Self {
- Self {
- context: Context::Fragment,
- raw,
- _spec: PhantomData,
- }
- }
-
- /// Creates a string consists of only `unreserved` string and percent-encoded triplets.
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let unreserved = "%a0-._~\u{03B1}";
- /// let unreserved_encoded = "%25a0-._~%CE%B1";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::unreserve(unreserved).to_string(),
- /// unreserved_encoded
- /// );
- ///
- /// let reserved = ":/?#[]@ !$&'()*+,;=";
- /// let reserved_encoded =
- /// "%3A%2F%3F%23%5B%5D%40%20%21%24%26%27%28%29%2A%2B%2C%3B%3D";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::unreserve(reserved).to_string(),
- /// reserved_encoded
- /// );
- /// # }
- /// ```
- #[inline]
- #[must_use]
- pub fn unreserve(raw: T) -> Self {
- Self {
- context: Context::Unreserve,
- raw,
- _spec: PhantomData,
- }
- }
-
- /// Percent-encodes characters only if they cannot appear anywhere in an IRI reference.
- ///
- /// `%` character will be always encoded. In other words, this conversion
- /// is not aware of percent-encoded triplets.
- ///
- /// Note that this encoding process does not guarantee that the resulting
- /// string is a valid IRI reference.
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::percent_encode::PercentEncoded;
- /// use iri_string::spec::UriSpec;
- ///
- /// let unreserved = "%a0-._~\u{03B1}";
- /// let unreserved_encoded = "%25a0-._~%CE%B1";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::characters(unreserved).to_string(),
- /// unreserved_encoded
- /// );
- ///
- /// let reserved = ":/?#[]@ !$&'()*+,;=";
- /// // Note that `%20` cannot appear directly in an IRI reference.
- /// let expected = ":/?#[]@%20!$&'()*+,;=";
- /// assert_eq!(
- /// PercentEncoded::<_, UriSpec>::characters(reserved).to_string(),
- /// expected
- /// );
- /// # }
- /// ```
- #[inline]
- #[must_use]
- pub fn characters(raw: T) -> Self {
- Self {
- context: Context::Character,
- raw,
- _spec: PhantomData,
- }
- }
-}
-
-impl<T: fmt::Display, S: Spec> fmt::Display for PercentEncoded<T, S> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// Filter that encodes a character before written if necessary.
- struct Filter<'a, 'b, S> {
- /// Encoding context.
- context: Context,
- /// Writer.
- writer: &'a mut fmt::Formatter<'b>,
- /// Spec.
- _spec: PhantomData<fn() -> S>,
- }
- impl<S: Spec> fmt::Write for Filter<'_, '_, S> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- s.chars().try_for_each(|c| self.write_char(c))
- }
- fn write_char(&mut self, c: char) -> fmt::Result {
- let is_valid_char = match (self.context, c.is_ascii()) {
- (Context::RegName, true) => char::is_ascii_regname(c as u8),
- (Context::RegName, false) => char::is_nonascii_regname::<S>(c),
- (Context::UserOrPassword, true) => {
- c != ':' && char::is_ascii_userinfo_ipvfutureaddr(c as u8)
- }
- (Context::UserOrPassword, false) => char::is_nonascii_userinfo::<S>(c),
- (Context::PathSegment, true) => char::is_ascii_pchar(c as u8),
- (Context::PathSegment, false) => S::is_nonascii_char_unreserved(c),
- (Context::Path, true) => c == '/' || char::is_ascii_pchar(c as u8),
- (Context::Path, false) => S::is_nonascii_char_unreserved(c),
- (Context::Query, true) => c == '/' || char::is_ascii_frag_query(c as u8),
- (Context::Query, false) => char::is_nonascii_query::<S>(c),
- (Context::Fragment, true) => c == '/' || char::is_ascii_frag_query(c as u8),
- (Context::Fragment, false) => char::is_nonascii_fragment::<S>(c),
- (Context::Unreserve, true) => char::is_ascii_unreserved(c as u8),
- (Context::Unreserve, false) => S::is_nonascii_char_unreserved(c),
- (Context::Character, true) => char::is_ascii_unreserved_or_reserved(c as u8),
- (Context::Character, false) => {
- S::is_nonascii_char_unreserved(c) || S::is_nonascii_char_private(c)
- }
- };
- if is_valid_char {
- self.writer.write_char(c)
- } else {
- write_pct_encoded_char(&mut self.writer, c)
- }
- }
- }
- let mut filter = Filter {
- context: self.context,
- writer: f,
- _spec: PhantomData::<fn() -> S>,
- };
- write!(filter, "{}", self.raw)
- }
-}
-
-/// Percent-encodes the given character and writes it.
-#[inline]
-fn write_pct_encoded_char<W: fmt::Write>(writer: &mut W, c: char) -> fmt::Result {
- let mut buf = [0_u8; 4];
- let buf = c.encode_utf8(&mut buf);
- buf.bytes().try_for_each(|b| write!(writer, "%{:02X}", b))
-}
diff --git a/vendor/iri-string/src/raw.rs b/vendor/iri-string/src/raw.rs
deleted file mode 100644
index 652f60a9..00000000
--- a/vendor/iri-string/src/raw.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-//! Raw IRI strings manipulation.
-//!
-//! Note that functions in this module may operates on raw `&str` types.
-//! It is caller's responsilibility to guarantee that the given string satisfies the precondition.
-
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-
-#[cfg(feature = "alloc")]
-use crate::parser::trusted as trusted_parser;
-
-/// Sets the fragment part to the given string.
-///
-/// Removes fragment part (and following `#` character) if `None` is given.
-#[cfg(feature = "alloc")]
-pub(crate) fn set_fragment(s: &mut String, fragment: Option<&str>) {
- remove_fragment(s);
- if let Some(fragment) = fragment {
- s.reserve(fragment.len() + 1);
- s.push('#');
- s.push_str(fragment);
- }
-}
-
-/// Removes the fragment part from the string.
-#[cfg(feature = "alloc")]
-#[inline]
-pub(crate) fn remove_fragment(s: &mut String) {
- if let Some(colon_pos) = s.find('#') {
- s.truncate(colon_pos);
- }
-}
-
-/// Splits the string into the prefix and the fragment part.
-///
-/// A leading `#` character is truncated if the fragment part exists.
-#[cfg(feature = "alloc")]
-pub(crate) fn split_fragment_owned(mut s: String) -> (String, Option<String>) {
- let prefix_len = match trusted_parser::split_fragment(&s) {
- (_, None) => return (s, None),
- (prefix, Some(_fragment)) => prefix.len(),
- };
-
- // `+ 1` is for leading `#` character.
- let fragment = s.split_off(prefix_len + 1);
- // Current `s` contains a trailing `#` character, which should be removed.
- {
- // Remove a trailing `#`.
- let hash = s.pop();
- assert_eq!(hash, Some('#'));
- }
- assert_eq!(s.len(), prefix_len);
-
- (s, Some(fragment))
-}
diff --git a/vendor/iri-string/src/resolve.rs b/vendor/iri-string/src/resolve.rs
deleted file mode 100644
index d29c6874..00000000
--- a/vendor/iri-string/src/resolve.rs
+++ /dev/null
@@ -1,344 +0,0 @@
-//! URI and IRI resolvers.
-//!
-//! # IRI resolution can fail without WHATWG URL Standard serialization
-//!
-//! ## Pure RFC 3986 algorithm
-//!
-//! Though this is not explicitly stated in RFC 3986, IRI resolution can fail.
-//! Below are examples:
-//!
-//! * base=`scheme:`, ref=`.///bar`.
-//! + Resulting IRI should have scheme `scheme` and path `//bar`, but does not have authority.
-//! * base=`scheme:foo`, ref=`.///bar`.
-//! + Resulting IRI should have scheme `scheme` and path `//bar`, but does not have authority.
-//! * base=`scheme:`, ref=`/..//baz`.
-//! + Resulting IRI should have scheme `scheme` and path `//bar`, but does not have authority.
-//! * base=`scheme:foo/bar`, ref=`..//baz`.
-//! + Resulting IRI should have scheme `scheme` and path `//bar`, but does not have authority.
-//!
-//! IRI without authority (note that this is different from "with empty authority")
-//! cannot have a path starting with `//`, since it is ambiguous and can be
-//! interpreted as an IRI with authority. For the above examples, `scheme://bar`
-//! is not valid output, as `bar` in `scheme://bar` will be interpreted as an
-//! authority, not a path.
-//!
-//! Thus, IRI resolution by pure RFC 3986 algorithm can fail for some abnormal
-//! cases.
-//!
-//! Note that this kind of failure can happen only when the base IRI has no
-//! authority and empty path. This would be rare in the wild, since many people
-//! would use an IRI with authority part, such as `http://`.
-//!
-//! If you are handling `scheme://`-style URIs and IRIs, don't worry about the
-//! failure. Currently no cases are known to fail when at least one of the base
-//! IRI or the relative IRI contains authorities.
-//!
-//! If you want this kind of abnormal IRI resolution to succeed and to be
-//! idempotent, check the resolution result using
-//! [`Normalized::ensure_rfc3986_normalizable`] (see the section below).
-//!
-//! ## WHATWG serialization
-//!
-//! To handle IRI resolution failure, WHATWG URL Standard defines serialization
-//! algorithm for this kind of result, and it makes IRI resolution (and even
-//! normalization) infallible and idempotent.
-//!
-//! IRI resolution and normalization provided by this crate automatically
-//! applies this special rule if necessary, so they are infallible. If you want
-//! to detect resolution/normalization failure, use
-//! [`Normalized::ensure_rfc3986_normalizable`] method.
-//!
-//! ## Examples
-//!
-//! ```
-//! # #[cfg(feature = "alloc")] {
-//! use iri_string::format::ToDedicatedString;
-//! use iri_string::types::{IriAbsoluteStr, IriReferenceStr};
-//!
-//! let base = IriAbsoluteStr::new("scheme:")?;
-//! {
-//! let reference = IriReferenceStr::new(".///not-a-host")?;
-//! let result = reference.resolve_against(base);
-//! assert!(result.ensure_rfc3986_normalizable().is_err());
-//! assert_eq!(result.to_dedicated_string(), "scheme:/.//not-a-host");
-//! }
-//!
-//! {
-//! let reference2 = IriReferenceStr::new("/..//not-a-host")?;
-//! // Resulting string will be `scheme://not-a-host`, but `not-a-host`
-//! // should be a path segment, not a host. So, the semantically correct
-//! // target IRI cannot be represented by RFC 3986 IRI resolution.
-//! let result2 = reference2.resolve_against(base);
-//! assert!(result2.ensure_rfc3986_normalizable().is_err());
-//!
-//! // Algorithm defined in WHATWG URL Standard addresses this case.
-//! assert_eq!(result2.to_dedicated_string(), "scheme:/.//not-a-host");
-//! }
-//! # }
-//! # Ok::<_, iri_string::validate::Error>(())
-//! ```
-
-use crate::components::RiReferenceComponents;
-use crate::normalize::{NormalizationInput, Normalized};
-use crate::spec::Spec;
-use crate::types::{RiAbsoluteStr, RiQueryStr, RiReferenceStr, RiStr};
-
-/// A resolver against the fixed base.
-#[derive(Debug, Clone, Copy)]
-pub struct FixedBaseResolver<'a, S: Spec> {
- /// Components of the base IRI.
- base_components: RiReferenceComponents<'a, S>,
-}
-
-impl<'a, S: Spec> FixedBaseResolver<'a, S> {
- /// Creates a new resolver with the given base.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # // `ToDedicatedString` is available only when
- /// # // `alloc` feature is enabled.
- /// #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::{IriAbsoluteStr, IriReferenceStr};
- ///
- /// let base = IriAbsoluteStr::new("http://example.com/base/")?;
- /// let resolver = FixedBaseResolver::new(base);
- ///
- /// let reference = IriReferenceStr::new("../there")?;
- /// let resolved = resolver.resolve(reference);
- ///
- /// assert_eq!(resolved.to_dedicated_string(), "http://example.com/there");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- pub fn new(base: &'a RiAbsoluteStr<S>) -> Self {
- Self {
- base_components: RiReferenceComponents::from(base.as_ref()),
- }
- }
-
- /// Returns the base.
- ///
- /// # Examples
- ///
- /// ```
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::{IriAbsoluteStr, IriReferenceStr};
- ///
- /// let base = IriAbsoluteStr::new("http://example.com/base/")?;
- /// let resolver = FixedBaseResolver::new(base);
- ///
- /// assert_eq!(resolver.base(), base);
- /// # Ok::<_, iri_string::validate::Error>(())
- /// ```
- #[must_use]
- pub fn base(&self) -> &'a RiAbsoluteStr<S> {
- // SAFETY: `base_components` can only be created from `&RiAbsoluteStr<S>`,
- // and the type of `base_components` does not allow modification of the
- // content after it is created.
- unsafe { RiAbsoluteStr::new_maybe_unchecked(self.base_components.iri().as_str()) }
- }
-}
-
-/// Components getters.
-///
-/// These getters are more efficient than calling through the result of `.base()`.
-impl<S: Spec> FixedBaseResolver<'_, S> {
- /// Returns the scheme.
- ///
- /// The following colon is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let base = IriAbsoluteStr::new("http://example.com/base/?query")?;
- /// let resolver = FixedBaseResolver::new(base);
- ///
- /// assert_eq!(resolver.scheme_str(), "http");
- /// assert_eq!(base.scheme_str(), "http");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn scheme_str(&self) -> &str {
- self.base_components
- .scheme_str()
- .expect("[validity] absolute IRI should have the scheme part")
- }
-
- /// Returns the authority.
- ///
- /// The leading `//` is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let base = IriAbsoluteStr::new("http://user:pass@example.com/base/?query")?;
- /// let resolver = FixedBaseResolver::new(base);
- ///
- /// assert_eq!(resolver.authority_str(), Some("user:pass@example.com"));
- /// assert_eq!(base.authority_str(), Some("user:pass@example.com"));
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_str(&self) -> Option<&str> {
- self.base_components.authority_str()
- }
-
- /// Returns the path.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let base = IriAbsoluteStr::new("http://user:pass@example.com/base/?query")?;
- /// let resolver = FixedBaseResolver::new(base);
- ///
- /// assert_eq!(resolver.path_str(), "/base/");
- /// assert_eq!(base.path_str(), "/base/");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn path_str(&self) -> &str {
- self.base_components.path_str()
- }
-
- /// Returns the query.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::{IriAbsoluteStr, IriQueryStr};
- ///
- /// let base = IriAbsoluteStr::new("http://user:pass@example.com/base/?query")?;
- /// let resolver = FixedBaseResolver::new(base);
- /// let query = IriQueryStr::new("query")?;
- ///
- /// assert_eq!(resolver.query(), Some(query));
- /// assert_eq!(base.query(), Some(query));
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query(&self) -> Option<&RiQueryStr<S>> {
- let query_raw = self.query_str()?;
- let query = RiQueryStr::new(query_raw)
- .expect("[validity] must be valid query if present in an absolute-IRI");
- Some(query)
- }
-
- /// Returns the query in a raw string slice.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let base = IriAbsoluteStr::new("http://user:pass@example.com/base/?query")?;
- /// let resolver = FixedBaseResolver::new(base);
- ///
- /// assert_eq!(resolver.query_str(), Some("query"));
- /// assert_eq!(base.query_str(), Some("query"));
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query_str(&self) -> Option<&str> {
- self.base_components.query_str()
- }
-}
-
-impl<'a, S: Spec> FixedBaseResolver<'a, S> {
- /// Resolves the given reference against the fixed base.
- ///
- /// The task returned by this method does **not** normalize the resolution
- /// result. However, `..` and `.` are recognized even when they are
- /// percent-encoded.
- ///
- /// # Failures
- ///
- /// This function itself does not fail, but resolution algorithm defined by
- /// RFC 3986 can fail. In that case, serialization algorithm defined by
- /// WHATWG URL Standard would be automatically applied.
- ///
- /// See the documentation of [`Normalized`].
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # // `ToDedicatedString` is available only when
- /// # // `alloc` feature is enabled.
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::{IriAbsoluteStr, IriReferenceStr};
- ///
- /// let base = IriAbsoluteStr::new("http://example.com/base/")?;
- /// let resolver = FixedBaseResolver::new(base);
- ///
- /// let reference = IriReferenceStr::new("../there")?;
- /// let resolved = resolver.resolve(reference);
- ///
- /// assert_eq!(resolved.to_dedicated_string(), "http://example.com/there");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// Note that `..` and `.` path segments are recognized even when they are
- /// percent-encoded.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # // `ToDedicatedString` is available only when
- /// # // `alloc` feature is enabled.
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::resolve::FixedBaseResolver;
- /// use iri_string::types::{IriAbsoluteStr, IriReferenceStr};
- ///
- /// let base = IriAbsoluteStr::new("HTTP://example.COM/base/base2/")?;
- /// let resolver = FixedBaseResolver::new(base);
- ///
- /// // `%2e%2e` is recognized as `..`.
- /// // However, `dot%2edot` is NOT normalized into `dot.dot`.
- /// let reference = IriReferenceStr::new("%2e%2e/../dot%2edot")?;
- /// let resolved = resolver.resolve(reference);
- ///
- /// // Resolved but not normalized.
- /// assert_eq!(resolved.to_dedicated_string(), "HTTP://example.COM/dot%2edot");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn resolve(&self, reference: &'a RiReferenceStr<S>) -> Normalized<'a, RiStr<S>> {
- let input = NormalizationInput::with_resolution_params(&self.base_components, reference);
- Normalized::from_input(input)
- }
-}
diff --git a/vendor/iri-string/src/spec.rs b/vendor/iri-string/src/spec.rs
deleted file mode 100644
index 21e8315e..00000000
--- a/vendor/iri-string/src/spec.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-//! IRI specs.
-
-use core::fmt;
-
-// Note that this MUST be private module.
-// See <https://rust-lang.github.io/api-guidelines/future-proofing.html> about
-// sealed trait.
-mod internal;
-
-/// A trait for spec types.
-///
-/// This trait is not intended to be implemented by crate users.
-// Note that all types which implement `Spec` also implement `SpecInternal`.
-pub trait Spec: internal::Sealed + Copy + fmt::Debug {}
-
-/// A type that represents specification of IRI.
-///
-/// About IRI, see [RFC 3987].
-///
-/// [RFC 3987]: https://tools.ietf.org/html/rfc3987
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum IriSpec {}
-
-impl Spec for IriSpec {}
-
-/// A type that represents specification of URI.
-///
-/// About URI, see [RFC 3986].
-///
-/// [RFC 3986]: https://tools.ietf.org/html/rfc3986
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum UriSpec {}
-
-impl Spec for UriSpec {}
diff --git a/vendor/iri-string/src/spec/internal.rs b/vendor/iri-string/src/spec/internal.rs
deleted file mode 100644
index 3ad2ee34..00000000
--- a/vendor/iri-string/src/spec/internal.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-//! A private module for sealed trait and internal implementations.
-//!
-//! Note that this MUST be a private module.
-//! See [Rust API Guidelines][sealed-trait] about the necessity of being private.
-//!
-//! [sealed-trait]:
-//! https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
-
-use crate::parser::char::is_ucschar;
-use crate::spec::{IriSpec, UriSpec};
-
-/// A trait to prohibit user-defined types from implementing `Spec`.
-///
-/// About sealed trait, see [Rust API Guidelines][future-proofing].
-///
-/// [future-proofing]: https://rust-lang.github.io/api-guidelines/future-proofing.html
-pub trait Sealed: SpecInternal {}
-
-impl Sealed for IriSpec {}
-impl Sealed for UriSpec {}
-
-/// Internal implementations for spec types.
-pub trait SpecInternal: Sized {
- /// Checks if the given non-ASCII character matches `unreserved` or `iunreserved` rule.
- #[must_use]
- fn is_nonascii_char_unreserved(c: char) -> bool;
- /// Checks if the given character matches `iprivate` rule.
- #[must_use]
- fn is_nonascii_char_private(c: char) -> bool;
-}
-
-impl SpecInternal for IriSpec {
- #[inline]
- fn is_nonascii_char_unreserved(c: char) -> bool {
- is_ucschar(c)
- }
-
- fn is_nonascii_char_private(c: char) -> bool {
- matches!(
- u32::from(c),
- 0xE000..=0xF8FF |
- 0xF_0000..=0xF_FFFD |
- 0x10_0000..=0x10_FFFD
- )
- }
-}
-
-impl SpecInternal for UriSpec {
- #[inline]
- fn is_nonascii_char_unreserved(_: char) -> bool {
- false
- }
-
- #[inline]
- fn is_nonascii_char_private(_: char) -> bool {
- false
- }
-}
diff --git a/vendor/iri-string/src/template.rs b/vendor/iri-string/src/template.rs
deleted file mode 100644
index 3c647ff2..00000000
--- a/vendor/iri-string/src/template.rs
+++ /dev/null
@@ -1,200 +0,0 @@
-//! Processor for [RFC 6570] URI Template.
-//!
-//! [RFC 6570]: https://www.rfc-editor.org/rfc/rfc6570.html
-//!
-//! # Usage
-//!
-//! 1. Prepare a template.
-//! * You can create a template as [`UriTemplateStr`]
-#![cfg_attr(
- feature = "alloc",
- doc = " type (borrowed) or [`UriTemplateString`] type (owned)."
-)]
-#![cfg_attr(not(feature = "alloc"), doc = " type.")]
-//! 2. Prepare a context.
-//! * Create a value of type that implements [`Context`] trait.
-#![cfg_attr(
- feature = "alloc",
- doc = " * Or, if you use [`SimpleContext`], insert key-value pairs into it."
-)]
-//! 3. Expand.
-//! * Pass the context to [`UriTemplateStr::expand`] method of the template.
-//! 4. Use the result.
-//! * Returned [`Expanded`] object can be directly printed since it
-//! implements [`Display`][`core::fmt::Display`] trait. Or, you can call
-//! `.to_string()` method of the `alloc::string::ToString` trait to
-//! convert it to a `String`.
-//!
-//! # Examples
-//!
-//! ## Custom context type
-//!
-//! For details, see [the documentation of `context` module][`context`].
-//!
-//! ```
-//! # use iri_string::template::Error;
-//! use core::fmt;
-//! use iri_string::spec::{IriSpec, Spec, UriSpec};
-//! use iri_string::template::UriTemplateStr;
-//! use iri_string::template::context::{Context, VarName, Visitor};
-//!
-//! struct UserInfo {
-//! username: &'static str,
-//! utf8_available: bool,
-//! }
-//!
-//! impl Context for UserInfo {
-//! fn visit<V: Visitor>(
-//! &self,
-//! visitor: V,
-//! ) -> V::Result {
-//! match visitor.var_name().as_str() {
-//! "username" => visitor.visit_string(self.username),
-//! "utf8" => {
-//! if self.utf8_available {
-//! // U+2713 CHECK MARK
-//! visitor.visit_string("\u{2713}")
-//! } else {
-//! visitor.visit_undefined()
-//! }
-//! }
-//! _ => visitor.visit_undefined()
-//! }
-//! }
-//! }
-//!
-//! let context = UserInfo {
-//! username: "foo",
-//! utf8_available: true,
-//! };
-//!
-//! let template = UriTemplateStr::new("/users/{username}{?utf8}")?;
-//!
-//! # #[cfg(feature = "alloc")] {
-//! assert_eq!(
-//! template.expand::<UriSpec, _>(&context)?.to_string(),
-//! "/users/foo?utf8=%E2%9C%93"
-//! );
-//! assert_eq!(
-//! template.expand::<IriSpec, _>(&context)?.to_string(),
-//! "/users/foo?utf8=\u{2713}"
-//! );
-//! # }
-//! # Ok::<_, Error>(())
-//! ```
-//!
-//! ## `SimpleContext` type (enabled by `alloc` feature flag)
-//!
-//! ```
-//! # use iri_string::template::Error;
-//! # #[cfg(feature = "alloc")] {
-//! use iri_string::spec::{IriSpec, UriSpec};
-//! use iri_string::template::UriTemplateStr;
-//! use iri_string::template::simple_context::SimpleContext;
-//!
-//! let mut context = SimpleContext::new();
-//! context.insert("username", "foo");
-//! // U+2713 CHECK MARK
-//! context.insert("utf8", "\u{2713}");
-//!
-//! let template = UriTemplateStr::new("/users/{username}{?utf8}")?;
-//!
-//! assert_eq!(
-//! template.expand::<UriSpec, _>(&context)?.to_string(),
-//! "/users/foo?utf8=%E2%9C%93"
-//! );
-//! assert_eq!(
-//! template.expand::<IriSpec, _>(&context)?.to_string(),
-//! "/users/foo?utf8=\u{2713}"
-//! );
-//! # }
-//! # Ok::<_, Error>(())
-//! ```
-//!
-#![cfg_attr(
- feature = "alloc",
- doc = "[`SimpleContext`]: `simple_context::SimpleContext`"
-)]
-mod components;
-pub mod context;
-mod error;
-mod expand;
-mod parser;
-#[cfg(feature = "alloc")]
-pub mod simple_context;
-mod string;
-
-pub use self::context::{Context, DynamicContext};
-#[cfg(feature = "alloc")]
-pub use self::error::CreationError;
-pub use self::error::Error;
-pub use self::expand::Expanded;
-#[cfg(feature = "alloc")]
-pub use self::string::UriTemplateString;
-pub use self::string::{UriTemplateStr, UriTemplateVariables};
-
-/// Deprecated old name of [`template::context::VarName`].
-///
-/// [`template::context::VarName`]: `components::VarName`
-#[deprecated(
- since = "0.7.1",
- note = "renamed (moved) to `template::context::VarName`"
-)]
-pub type VarName<'a> = self::components::VarName<'a>;
-
-/// Variable value type.
-#[derive(Debug, Clone, Copy)]
-enum ValueType {
- /// Undefined (i.e. null).
- Undefined,
- /// String value.
- String,
- /// List.
- List,
- /// Associative array.
- Assoc,
-}
-
-impl ValueType {
- /// Returns the value type for an undefined variable.
- #[inline]
- #[must_use]
- pub const fn undefined() -> Self {
- ValueType::Undefined
- }
-
- /// Returns the value type for a string variable.
- #[inline]
- #[must_use]
- pub const fn string() -> Self {
- ValueType::String
- }
-
- /// Returns the value type for an empty list variable.
- #[inline]
- #[must_use]
- pub const fn empty_list() -> Self {
- ValueType::Undefined
- }
-
- /// Returns the value type for a nonempty list variable.
- #[inline]
- #[must_use]
- pub const fn nonempty_list() -> Self {
- ValueType::List
- }
-
- /// Returns the value type for an empty associative array variable.
- #[inline]
- #[must_use]
- pub const fn empty_assoc() -> Self {
- ValueType::Undefined
- }
-
- /// Returns the value type for a nonempty associative array variable.
- #[inline]
- #[must_use]
- pub const fn nonempty_assoc() -> Self {
- ValueType::Assoc
- }
-}
diff --git a/vendor/iri-string/src/template/components.rs b/vendor/iri-string/src/template/components.rs
deleted file mode 100644
index 7eb83a58..00000000
--- a/vendor/iri-string/src/template/components.rs
+++ /dev/null
@@ -1,332 +0,0 @@
-//! Syntax components of URI templates.
-
-use core::mem;
-
-use crate::parser::str::find_split_hole;
-use crate::template::error::Error;
-use crate::template::parser::validate as validate_parser;
-
-/// Expression body.
-///
-/// This does not contain the wrapping braces (`{` and `}`).
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(super) struct ExprBody<'a>(&'a str);
-
-impl<'a> ExprBody<'a> {
- /// Creates a new expression body.
- ///
- /// # Precondition
- ///
- /// The given string should be a valid expression body.
- #[inline]
- #[must_use]
- pub(super) fn new(s: &'a str) -> Self {
- debug_assert!(
- !s.is_empty(),
- "[precondition] valid expression body is not empty"
- );
-
- Self(s)
- }
-
- /// Decomposes the expression into an `operator` and `variable-list`.
- ///
- /// # Panics
- ///
- /// May panic if the input is invalid.
- #[must_use]
- pub(super) fn decompose(&self) -> (Operator, VarListStr<'a>) {
- debug_assert!(
- !self.0.is_empty(),
- "[precondition] valid expression body is not empty"
- );
- let first = self.0.as_bytes()[0];
- if first.is_ascii_alphanumeric() || (first == b'_') || (first == b'%') {
- // The first byte is a part of the variable list.
- (Operator::String, VarListStr::new(self.0))
- } else {
- let op = Operator::from_byte(first).unwrap_or_else(|| {
- unreachable!(
- "[precondition] valid expression has (optional) \
- valid operator, but got a byte {first:#02x?}"
- )
- });
- (op, VarListStr::new(&self.0[1..]))
- }
- }
-
- /// Returns the raw expression in a string slice.
- #[inline]
- #[must_use]
- pub(super) fn as_str(&self) -> &'a str {
- self.0
- }
-}
-
-/// Variable name.
-// QUESTION: Should hexdigits in percent-encoded triplets be compared case sensitively?
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct VarName<'a>(&'a str);
-
-impl<'a> VarName<'a> {
- /// Creates a `VarName` from the trusted string.
- ///
- /// # Precondition
- ///
- /// The given string should be a valid variable name.
- #[inline]
- #[must_use]
- pub(super) fn from_trusted(s: &'a str) -> Self {
- Self(s)
- }
-
- /// Creates a `VarName` from the string.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// use iri_string::template::context::VarName;
- ///
- /// let name = VarName::new("hello")?;
- /// assert_eq!(name.as_str(), "hello");
- ///
- /// assert!(VarName::new("0+non-variable-name").is_err());
- ///
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn new(s: &'a str) -> Result<Self, Error> {
- match validate_parser::validate_varname(s, 0) {
- Ok(_) => Ok(Self::from_trusted(s)),
- Err(e) => Err(e),
- }
- }
-
- /// Returns the varibale name.
- #[inline]
- #[must_use]
- pub fn as_str(&self) -> &'a str {
- self.0
- }
-}
-
-/// Variable specifier.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct VarSpec<'a> {
- /// Variable name.
- name: VarName<'a>,
- /// Variable modifier.
- modifier: Modifier,
-}
-
-impl<'a> VarSpec<'a> {
- /// Returns the varibale name.
- #[inline]
- #[must_use]
- pub(super) fn name(&self) -> VarName<'a> {
- self.name
- }
-
- /// Returns the modifier.
- #[inline]
- #[must_use]
- pub(super) fn modifier(&self) -> Modifier {
- self.modifier
- }
-
- /// Parses the trusted varspec string.
- ///
- /// # Panics
- ///
- /// May panic if the input is invalid.
- #[must_use]
- pub(super) fn parse_trusted(s: &'a str) -> Self {
- if let Some(varname) = s.strip_suffix('*') {
- // `varname "*"`.
- return Self {
- name: VarName::from_trusted(varname),
- modifier: Modifier::Explode,
- };
- }
- // `varname ":" max-length` or `varname`.
- match find_split_hole(s, b':') {
- Some((varname, max_len)) => {
- let max_len: u16 = max_len
- .parse()
- .expect("[precondition] the input should be valid `varspec`");
- Self {
- name: VarName::from_trusted(varname),
- modifier: Modifier::MaxLen(max_len),
- }
- }
- None => Self {
- name: VarName(s),
- modifier: Modifier::None,
- },
- }
- }
-}
-
-/// Variable list.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(super) struct VarListStr<'a>(&'a str);
-
-impl<'a> VarListStr<'a> {
- /// Creates a new variable list.
- ///
- /// # Precondition
- ///
- /// The given string should be a valid variable list.
- #[inline]
- #[must_use]
- pub(super) fn new(s: &'a str) -> Self {
- Self(s)
- }
-}
-
-impl<'a> IntoIterator for VarListStr<'a> {
- type IntoIter = VarListIter<'a>;
- type Item = (usize, VarSpec<'a>);
-
- #[inline]
- fn into_iter(self) -> Self::IntoIter {
- VarListIter { rest: self.0 }
- }
-}
-
-/// Iterator of variable specs.
-#[derive(Debug, Clone)]
-pub(super) struct VarListIter<'a> {
- /// Remaining input.
- rest: &'a str,
-}
-
-impl<'a> Iterator for VarListIter<'a> {
- /// A pair of the length of the varspec and the varspec itself.
- type Item = (usize, VarSpec<'a>);
-
- fn next(&mut self) -> Option<Self::Item> {
- match find_split_hole(self.rest, b',') {
- Some((prefix, new_rest)) => {
- self.rest = new_rest;
- Some((prefix.len(), VarSpec::parse_trusted(prefix)))
- }
- None => {
- if self.rest.is_empty() {
- None
- } else {
- Some((
- self.rest.len(),
- VarSpec::parse_trusted(mem::take(&mut self.rest)),
- ))
- }
- }
- }
- }
-}
-
-/// Variable modifier.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(super) enum Modifier {
- /// No modifiers.
- None,
- /// Max length, greater than 0 and less than 10000.
- MaxLen(u16),
- /// Explode the variable, e.g. the var spec has `*`.
- Explode,
-}
-
-/// Operator that is possibly reserved for future extension.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(super) enum MaybeOperator {
- /// Working operator.
- Operator(Operator),
- /// Reserved for future extensions.
- Reserved(OperatorReservedForFuture),
-}
-
-impl MaybeOperator {
- /// Returns the operator for the given character.
- pub(super) fn from_byte(b: u8) -> Option<Self> {
- match b {
- b'+' => Some(Self::Operator(Operator::Reserved)),
- b'#' => Some(Self::Operator(Operator::Fragment)),
- b'.' => Some(Self::Operator(Operator::Label)),
- b'/' => Some(Self::Operator(Operator::PathSegments)),
- b';' => Some(Self::Operator(Operator::PathParams)),
- b'?' => Some(Self::Operator(Operator::FormQuery)),
- b'&' => Some(Self::Operator(Operator::FormQueryCont)),
- b'=' => Some(Self::Reserved(OperatorReservedForFuture::Equals)),
- b',' => Some(Self::Reserved(OperatorReservedForFuture::Comma)),
- b'!' => Some(Self::Reserved(OperatorReservedForFuture::Exclamation)),
- b'@' => Some(Self::Reserved(OperatorReservedForFuture::AtSign)),
- b'|' => Some(Self::Reserved(OperatorReservedForFuture::Pipe)),
- _ => None,
- }
- }
-}
-
-/// Working operator.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(super) enum Operator {
- /// No operator. String expansion.
- String,
- /// Reserved expansion by `+`.
- Reserved,
- /// Fragment expansion by `#`.
- Fragment,
- /// Label expansion by `.`.
- Label,
- /// Path segments by `/`.
- PathSegments,
- /// Path-style parameters by `;`.
- PathParams,
- /// Form-style query by `?`.
- FormQuery,
- /// Form-style query continuation by `&`.
- FormQueryCont,
-}
-
-impl Operator {
- /// Returns the operator for the given character.
- #[must_use]
- pub(super) fn from_byte(b: u8) -> Option<Self> {
- match b {
- b'+' => Some(Self::Reserved),
- b'#' => Some(Self::Fragment),
- b'.' => Some(Self::Label),
- b'/' => Some(Self::PathSegments),
- b';' => Some(Self::PathParams),
- b'?' => Some(Self::FormQuery),
- b'&' => Some(Self::FormQueryCont),
- _ => None,
- }
- }
-
- /// Returns the string length of the operator.
- #[inline]
- #[must_use]
- pub(super) const fn len(self) -> usize {
- if matches!(self, Self::String) {
- 0
- } else {
- 1
- }
- }
-}
-
-/// Operator reserved for future extension.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(super) enum OperatorReservedForFuture {
- /// Reserved `=` operator.
- Equals,
- /// Reserved `,` operator.
- Comma,
- /// Reserved `!` operator.
- Exclamation,
- /// Reserved `@` operator.
- AtSign,
- /// Reserved `|` operator.
- Pipe,
-}
diff --git a/vendor/iri-string/src/template/context.rs b/vendor/iri-string/src/template/context.rs
deleted file mode 100644
index ea3f14bb..00000000
--- a/vendor/iri-string/src/template/context.rs
+++ /dev/null
@@ -1,339 +0,0 @@
-//! Template expansion context.
-//!
-//! # Examples
-//!
-//! 1. Define your context type.
-//! 2. Implement [`Context`] trait (and [`Context::visit`] method) for the type.
-//! 1. Get variable name by [`Visitor::var_name`] method.
-//! 2. Feed the corresponding value(s) by one of `Visitor::visit_*` methods.
-//!
-//! Note that contexts should return consistent result across multiple visits for
-//! the same variable. In other words, `Context::visit` should return the same
-//! result for the same `Visitor::var_name()` during the context is borrowed.
-//! If this condition is violated, the URI template processor can return
-//! invalid result or panic at worst.
-//!
-//! ```
-//! use iri_string::template::context::{Context, Visitor, ListVisitor, AssocVisitor};
-//!
-//! struct MyContext {
-//! name: &'static str,
-//! id: u64,
-//! tags: &'static [&'static str],
-//! children: &'static [(&'static str, usize)],
-//! }
-//!
-//! impl Context for MyContext {
-//! fn visit<V: Visitor>(&self, visitor: V) -> V::Result {
-//! let name = visitor.var_name().as_str();
-//! match name {
-//! "name" => visitor.visit_string(self.name),
-//! "id" => visitor.visit_string(self.id),
-//! "tags" => visitor.visit_list().visit_items_and_finish(self.tags),
-//! "children" => visitor
-//! .visit_assoc()
-//! .visit_entries_and_finish(self.children.iter().copied()),
-//! _ => visitor.visit_undefined(),
-//! }
-//! }
-//! }
-//! ```
-//
-// # Developers note
-//
-// Visitor types **should not** be cloneable in order to enforce just one
-// visitor is used to visit a variable. If visitors are cloneable, it can make
-// the wrong usage to be available, i.e. storing cloned visitors somewhere and
-// using the wrong one.
-//
-// However, if visitors are made cloneable by any chance, it does not indicate
-// the whole implementation will be broken. Users can only use the visitors
-// through visitor traits (and their API do not allow cloning), so the logic
-// would work as expected if the internal usage of the visitors are correct.
-// Making visitors noncloneable is an optional safety guard (with no overhead).
-
-use core::fmt;
-use core::ops::ControlFlow;
-
-pub use crate::template::components::VarName;
-
-/// A trait for types that can behave as a static URI template expansion context.
-///
-/// This type is for use with [`UriTemplateStr::expand`] method.
-///
-/// See [the module documentation][`crate::template`] for usage.
-///
-/// [`UriTemplateStr::expand`]: `crate::template::UriTemplateStr::expand`
-pub trait Context: Sized {
- /// Visits a variable.
- ///
- /// To get variable name, use [`Visitor::var_name()`].
- #[must_use]
- fn visit<V: Visitor>(&self, visitor: V) -> V::Result;
-}
-
-/// A trait for types that can behave as a dynamic (mutable) URI template expansion context.
-///
-/// This type is for use with [`UriTemplateStr::expand_dynamic`] method and its
-/// family.
-///
-/// Note that "dynamic" here does not mean that the value of variables can
-/// change during a template expansion. The value should be fixed and consistent
-/// during each expansion, but the context is allowed to mutate itself if it
-/// does not break this rule.
-///
-/// # Exmaples
-///
-/// ```
-/// # #[cfg(feature = "alloc")]
-/// # extern crate alloc;
-/// # use iri_string::template::Error;
-/// # #[cfg(feature = "alloc")] {
-/// # use alloc::string::String;
-/// use iri_string::template::UriTemplateStr;
-/// use iri_string::template::context::{DynamicContext, Visitor, VisitPurpose};
-/// use iri_string::spec::UriSpec;
-///
-/// struct MyContext<'a> {
-/// /// Target path.
-/// target: &'a str,
-/// /// Username.
-/// username: Option<&'a str>,
-/// /// A flag to remember whether the URI template
-/// /// attempted to use `username` variable.
-/// username_visited: bool,
-/// }
-///
-/// impl DynamicContext for MyContext<'_> {
-/// fn on_expansion_start(&mut self) {
-/// // Reset the state.
-/// self.username_visited = false;
-/// }
-/// fn visit_dynamic<V: Visitor>(&mut self, visitor: V) -> V::Result {
-/// match visitor.var_name().as_str() {
-/// "target" => visitor.visit_string(self.target),
-/// "username" => {
-/// if visitor.purpose() == VisitPurpose::Expand {
-/// // The variable `username` is being used
-/// // on the template expansion.
-/// // Don't care whether `username` is defined or not.
-/// self.username_visited = true;
-/// }
-/// if let Some(username) = &self.username {
-/// visitor.visit_string(username)
-/// } else {
-/// visitor.visit_undefined()
-/// }
-/// }
-/// _ => visitor.visit_undefined(),
-/// }
-/// }
-/// }
-///
-/// let mut context = MyContext {
-/// target: "/posts/1",
-/// username: Some("the_admin"),
-/// username_visited: false,
-/// };
-/// let mut buf = String::new();
-///
-/// // No access to the variable `username`.
-/// let template1 = UriTemplateStr::new("{+target}")?;
-/// template1.expand_dynamic::<UriSpec, _, _>(&mut buf, &mut context)?;
-/// assert_eq!(buf, "/posts/1");
-/// assert!(!context.username_visited);
-///
-/// buf.clear();
-/// // Will access to the variable `username`.
-/// let template2 = UriTemplateStr::new("{+target}{?username}")?;
-/// template2.expand_dynamic::<UriSpec, _, _>(&mut buf, &mut context)?;
-/// assert_eq!(buf, "/posts/1?username=the_admin");
-/// assert!(context.username_visited);
-///
-/// buf.clear();
-/// context.username = None;
-/// // Will access to the variable `username` but it is undefined.
-/// template2.expand_dynamic::<UriSpec, _, _>(&mut buf, &mut context)?;
-/// assert_eq!(buf, "/posts/1");
-/// assert!(
-/// context.username_visited,
-/// "`MyContext` can know and remember whether `visit_dynamic()` is called
-/// for `username`, even if its value is undefined"
-/// );
-/// # }
-/// # Ok::<_, Error>(())
-/// ```
-///
-/// [`UriTemplateStr::expand_dynamic`]: `crate::template::UriTemplateStr::expand_dynamic`
-pub trait DynamicContext: Sized {
- /// Visits a variable.
- ///
- /// To get variable name, use [`Visitor::var_name()`].
- ///
- /// # Restriction
- ///
- /// The visit results should be consistent and unchanged between the last
- /// time [`on_expansion_start`][`Self::on_expansion_start`] was called and
- /// the next time [`on_expansion_end`][`Self::on_expansion_end`] will be
- /// called. If this condition is violated, template expansion will produce
- /// wrong result or may panic at worst.
- #[must_use]
- fn visit_dynamic<V: Visitor>(&mut self, visitor: V) -> V::Result;
-
- /// A callback that is called before the expansion of a URI template.
- #[inline]
- fn on_expansion_start(&mut self) {}
-
- /// A callback that is called after the expansion of a URI template.
- #[inline]
- fn on_expansion_end(&mut self) {}
-}
-
-impl<C: Context> DynamicContext for C {
- #[inline]
- fn visit_dynamic<V: Visitor>(&mut self, visitor: V) -> V::Result {
- self.visit(visitor)
- }
-}
-
-/// A purpose of a visit.
-///
-/// This enum is nonexhaustive since this partially exposes the internal
-/// implementation of the template expansion, and thus this is subject to
-/// change.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum VisitPurpose {
- /// A visit for type checking.
- Typecheck,
- /// A visit for template expansion to retrieve the value.
- Expand,
-}
-
-/// Variable visitor.
-///
-/// See [the module documentation][self] for usage.
-// NOTE (internal): Visitor types **should not** be cloneable.
-pub trait Visitor: Sized + private::Sealed {
- /// Result of the visit.
- type Result;
- /// List visitor.
- type ListVisitor: ListVisitor<Result = Self::Result>;
- /// Associative array visitor.
- type AssocVisitor: AssocVisitor<Result = Self::Result>;
-
- /// Returns the name of the variable to visit.
- #[must_use]
- fn var_name(&self) -> VarName<'_>;
- /// Returns the purpose of the visit.
- ///
- /// The template expansion algorithm checks the types for some variables
- /// depending on its usage. To get the usage count correctly, you should
- /// only count visits with [`VisitPurpose::Expand`].
- ///
- /// If you need to know whether the variable is accessed and does not
- /// need dynamic context generation or access counts, consider using
- /// [`UriTemplateStr::variables`] method to iterate the variables in the
- /// URI template.
- ///
- /// [`UriTemplateStr::variables`]: `crate::template::UriTemplateStr::variables`
- #[must_use]
- fn purpose(&self) -> VisitPurpose;
- /// Visits an undefined variable, i.e. indicates that the requested variable is unavailable.
- #[must_use]
- fn visit_undefined(self) -> Self::Result;
- /// Visits a string variable.
- #[must_use]
- fn visit_string<T: fmt::Display>(self, v: T) -> Self::Result;
- /// Visits a list variable.
- #[must_use]
- fn visit_list(self) -> Self::ListVisitor;
- /// Visits an associative array variable.
- #[must_use]
- fn visit_assoc(self) -> Self::AssocVisitor;
-}
-
-/// List visitor.
-///
-/// See [the module documentation][self] for usage.
-// NOTE (internal): Visitor types **should not** be cloneable.
-pub trait ListVisitor: Sized + private::Sealed {
- /// Result of the visit.
- type Result;
-
- /// Visits an item.
- ///
- /// If this returned `ControlFlow::Break(v)`, [`Context::visit`] should also
- /// return this `v`.
- ///
- /// To feed multiple items at once, do
- /// `items.into_iter().try_for_each(|item| self.visit_item(item))` for example.
- #[must_use]
- fn visit_item<T: fmt::Display>(&mut self, item: T) -> ControlFlow<Self::Result>;
- /// Finishes visiting the list.
- #[must_use]
- fn finish(self) -> Self::Result;
-
- /// Visits items and finish.
- #[must_use]
- fn visit_items_and_finish<T, I>(mut self, items: I) -> Self::Result
- where
- T: fmt::Display,
- I: IntoIterator<Item = T>,
- {
- match items.into_iter().try_for_each(|item| self.visit_item(item)) {
- ControlFlow::Break(v) => v,
- ControlFlow::Continue(()) => self.finish(),
- }
- }
-}
-
-/// Associative array visitor.
-///
-/// See [the module documentation][self] for usage.
-// NOTE (internal): Visitor types **should not** be cloneable.
-pub trait AssocVisitor: Sized + private::Sealed {
- /// Result of the visit.
- type Result;
-
- /// Visits an entry.
- ///
- /// If this returned `ControlFlow::Break(v)`, [`Context::visit`] should also
- /// return this `v`.
- ///
- /// To feed multiple items at once, do
- /// `entries.into_iter().try_for_each(|(key, value)| self.visit_entry(key, value))`
- /// for example.
- #[must_use]
- fn visit_entry<K: fmt::Display, V: fmt::Display>(
- &mut self,
- key: K,
- value: V,
- ) -> ControlFlow<Self::Result>;
- /// Finishes visiting the associative array.
- #[must_use]
- fn finish(self) -> Self::Result;
-
- /// Visits entries and finish.
- #[must_use]
- fn visit_entries_and_finish<K, V, I>(mut self, entries: I) -> Self::Result
- where
- K: fmt::Display,
- V: fmt::Display,
- I: IntoIterator<Item = (K, V)>,
- {
- match entries
- .into_iter()
- .try_for_each(|(key, value)| self.visit_entry(key, value))
- {
- ControlFlow::Break(v) => v,
- ControlFlow::Continue(()) => self.finish(),
- }
- }
-}
-
-/// Private module to put the trait to seal.
-pub(super) mod private {
- /// A trait for visitor types of variables in a context.
- pub trait Sealed {}
-}
diff --git a/vendor/iri-string/src/template/error.rs b/vendor/iri-string/src/template/error.rs
deleted file mode 100644
index f5206a4b..00000000
--- a/vendor/iri-string/src/template/error.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-//! Errors related to URI templates.
-
-use core::fmt;
-
-#[cfg(feature = "std")]
-use std::error;
-
-/// Template construction and expansion error kind.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(super) enum ErrorKind {
- /// Cannot write to the backend.
- WriteFailed,
- /// Expression is not closed.
- ExpressionNotClosed,
- /// Invalid character.
- InvalidCharacter,
- /// Invalid expression.
- InvalidExpression,
- /// Invalid percent-encoded triplets.
- InvalidPercentEncoding,
- /// Invalid UTF-8 bytes.
- InvalidUtf8,
- /// Unexpected value type for the variable.
- UnexpectedValueType,
- /// Unsupported operator, including operators reserved for future.
- UnsupportedOperator,
-}
-
-impl ErrorKind {
- /// Returns the error message.
- #[must_use]
- fn as_str(self) -> &'static str {
- match self {
- Self::WriteFailed => "failed to write to the backend writer",
- Self::ExpressionNotClosed => "expression not closed",
- Self::InvalidCharacter => "invalid character",
- Self::InvalidExpression => "invalid expression",
- Self::InvalidPercentEncoding => "invalid percent-encoded triplets",
- Self::InvalidUtf8 => "invalid utf-8 byte sequence",
- Self::UnexpectedValueType => "unexpected value type for the variable",
- Self::UnsupportedOperator => "unsupported operator",
- }
- }
-}
-
-/// Template construction and expansion error.
-///
-// Note that this type should implement `Copy` trait.
-// To return additional non-`Copy` data as an error, use wrapper type
-// (as `std::string::FromUtf8Error` contains `std::str::Utf8Error`).
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct Error {
- /// Error kind.
- kind: ErrorKind,
- /// Location (byte position of the error).
- location: usize,
-}
-
-impl Error {
- /// Creates a new `Error`.
- ///
- /// For internal use.
- #[inline]
- #[must_use]
- pub(super) fn new(kind: ErrorKind, location: usize) -> Self {
- Self { kind, location }
- }
-
- /// Returns the byte position the error is detected.
- ///
- /// NOTE: This is not a part of the public API since the value to be
- /// returned (i.e., the definition of the "position" of an error) is not
- /// guaranteed to be stable.
- #[cfg(test)]
- pub(super) fn location(&self) -> usize {
- self.location
- }
-}
-
-impl fmt::Display for Error {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(
- f,
- "invalid URI template: {} (at {}-th byte)",
- self.kind.as_str(),
- self.location
- )
- }
-}
-
-#[cfg(feature = "std")]
-impl error::Error for Error {}
-
-/// Error on conversion into a URI template type.
-// TODO: Unifiable to `types::CreationError`?
-#[cfg(feature = "alloc")]
-pub struct CreationError<T> {
- /// Soruce data.
- source: T,
- /// Validation error.
- error: Error,
-}
-
-#[cfg(feature = "alloc")]
-impl<T> CreationError<T> {
- /// Returns the source data.
- #[must_use]
- pub fn into_source(self) -> T {
- self.source
- }
-
- /// Returns the validation error.
- #[must_use]
- pub fn validation_error(&self) -> Error {
- self.error
- }
-
- /// Creates a new `CreationError`.
- #[must_use]
- pub(crate) fn new(error: Error, source: T) -> Self {
- Self { source, error }
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<T: fmt::Debug> fmt::Debug for CreationError<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("CreationError")
- .field("source", &self.source)
- .field("error", &self.error)
- .finish()
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<T: Clone> Clone for CreationError<T> {
- fn clone(&self) -> Self {
- Self {
- source: self.source.clone(),
- error: self.error,
- }
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<T> fmt::Display for CreationError<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.error.fmt(f)
- }
-}
-
-#[cfg(feature = "std")]
-impl<T: fmt::Debug> error::Error for CreationError<T> {}
diff --git a/vendor/iri-string/src/template/expand.rs b/vendor/iri-string/src/template/expand.rs
deleted file mode 100644
index 605043ab..00000000
--- a/vendor/iri-string/src/template/expand.rs
+++ /dev/null
@@ -1,1039 +0,0 @@
-//! Expansion.
-
-use core::fmt::{self, Write as _};
-use core::marker::PhantomData;
-use core::mem;
-use core::ops::ControlFlow;
-
-#[cfg(feature = "alloc")]
-use alloc::string::{String, ToString};
-
-use crate::parser::str::{find_split, find_split_hole};
-use crate::parser::str::{process_percent_encoded_best_effort, PctEncodedFragments};
-use crate::percent_encode::PercentEncoded;
-use crate::spec::Spec;
-use crate::template::components::{ExprBody, Modifier, Operator, VarName, VarSpec};
-use crate::template::context::{
- private::Sealed as VisitorSealed, AssocVisitor, Context, DynamicContext, ListVisitor,
- VisitPurpose, Visitor,
-};
-use crate::template::error::{Error, ErrorKind};
-use crate::template::{UriTemplateStr, ValueType};
-#[cfg(feature = "alloc")]
-use crate::types;
-
-/// A chunk in a template string.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(super) enum Chunk<'a> {
- /// Literal.
- Literal(&'a str),
- /// Expression excluding the wrapping braces.
- Expr(ExprBody<'a>),
-}
-
-/// Iterator of template chunks.
-#[derive(Debug, Clone)]
-pub(super) struct Chunks<'a> {
- /// Template.
- template: &'a str,
-}
-
-impl<'a> Chunks<'a> {
- /// Creates a new iterator.
- #[inline]
- #[must_use]
- pub(super) fn new(template: &'a UriTemplateStr) -> Self {
- Self {
- template: template.as_str(),
- }
- }
-}
-
-impl<'a> Iterator for Chunks<'a> {
- type Item = Chunk<'a>;
-
- fn next(&mut self) -> Option<Self::Item> {
- if self.template.is_empty() {
- return None;
- }
- match find_split(self.template, b'{') {
- Some(("", _)) => {
- let (expr_body, rest) = find_split_hole(&self.template[1..], b'}')
- .expect("[validity] expression inside a template must be closed");
- self.template = rest;
- Some(Chunk::Expr(ExprBody::new(expr_body)))
- }
- Some((lit, rest)) => {
- self.template = rest;
- Some(Chunk::Literal(lit))
- }
- None => Some(Chunk::Literal(mem::take(&mut self.template))),
- }
- }
-}
-
-/// Template expansion result.
-#[derive(Debug, Clone, Copy)]
-pub struct Expanded<'a, S, C> {
- /// Compiled template.
- template: &'a UriTemplateStr,
- /// Context.
- context: &'a C,
- /// Spec.
- _spec: PhantomData<fn() -> S>,
-}
-
-impl<'a, S: Spec, C: Context> Expanded<'a, S, C> {
- /// Creates a new `Expanded` object.
- #[inline]
- pub(super) fn new(template: &'a UriTemplateStr, context: &'a C) -> Result<Self, Error> {
- Self::typecheck_context(template, context)?;
- Ok(Self {
- template,
- context,
- _spec: PhantomData,
- })
- }
-
- /// Checks if the types of variables are allowed for the corresponding expressions in the template.
- fn typecheck_context(template: &UriTemplateStr, context: &C) -> Result<(), Error> {
- let mut pos = 0;
- for chunk in Chunks::new(template) {
- let (expr_len, (op, varlist)) = match chunk {
- Chunk::Expr(expr_body) => (expr_body.as_str().len(), expr_body.decompose()),
- Chunk::Literal(lit) => {
- pos += lit.len();
- continue;
- }
- };
- // +2: wrapping braces (`{` and `}`).
- let chunk_end_pos = pos + expr_len + 2;
- // +1: opening brace `{`.
- pos += op.len() + 1;
- for (varspec_len, varspec) in varlist {
- let ty = context.visit(TypeVisitor::new(varspec.name()));
- let modifier = varspec.modifier();
-
- if matches!(modifier, Modifier::MaxLen(_))
- && matches!(ty, ValueType::List | ValueType::Assoc)
- {
- // > Prefix modifiers are not applicable to variables that
- // > have composite values.
- //
- // --- [RFC 6570 Section 2.4.1. Prefix](https://www.rfc-editor.org/rfc/rfc6570.html#section-2.4.1)
- return Err(Error::new(ErrorKind::UnexpectedValueType, pos));
- }
-
- // +1: A trailing comman (`,`) or a closing brace (`}`).
- pos += varspec_len + 1;
- }
- assert_eq!(pos, chunk_end_pos);
- }
- Ok(())
- }
-}
-
-impl<S: Spec, C: Context> fmt::Display for Expanded<'_, S, C> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for chunk in Chunks::new(self.template) {
- let expr = match chunk {
- Chunk::Literal(lit) => {
- f.write_str(lit)?;
- continue;
- }
- Chunk::Expr(body) => body,
- };
- expand::<S, _>(f, expr, self.context)?;
- }
-
- Ok(())
- }
-}
-
-/// Implement `TryFrom<Expanded<...>> for SomeUriStringType`.
-macro_rules! impl_try_from_expanded {
- ($ty_outer:ident) => {
- #[cfg(feature = "alloc")]
- impl<S: Spec, C: Context> TryFrom<Expanded<'_, S, C>> for types::$ty_outer<S> {
- type Error = types::CreationError<String>;
-
- #[inline]
- fn try_from(v: Expanded<'_, S, C>) -> Result<Self, Self::Error> {
- Self::try_from(v.to_string())
- }
- }
- };
-}
-
-// Not implementing `TryFrom<Expand<...>>` for query and fragment strings
-// since they cannot behave as a query or a fragment only by themselves.
-// Query strings in practical starts with `?` prefix but `RiQueryStr{,ing}`
-// strips that, and so do fragment strings (but `#` instead of `?`).
-// Because of this, query and fragment string types won't be used to represent
-// a relative IRIs without combining the prefix.
-//
-// In contrast, RFC 6570 URI Template expects that the users are constructing a
-// "working" IRIs, including the necessary prefixes for syntax components.
-// For example, fragment expansion `{#var}`, where `var` is "hello", expands to
-// `#hello`, including the prefix `#`. This means that a URI template will be
-// used to generate neither `RiQueryStr{,ing}` nor `RiFragmentStr{,ing}` strings.
-impl_try_from_expanded!(RiAbsoluteString);
-impl_try_from_expanded!(RiReferenceString);
-impl_try_from_expanded!(RiRelativeString);
-impl_try_from_expanded!(RiString);
-
-/// Expands the whole template with the dynamic context.
-pub(super) fn expand_whole_dynamic<S: Spec, W: fmt::Write, C: DynamicContext>(
- template: &UriTemplateStr,
- writer: &mut W,
- context: &mut C,
-) -> Result<(), Error> {
- context.on_expansion_start();
- let result = expand_whole_dynamic_impl::<S, W, C>(template, writer, context);
- context.on_expansion_end();
- result
-}
-
-/// Expands the whole template with the dynamic context.
-///
-/// Note that the caller is responsible to set up or finalize the `context`.
-fn expand_whole_dynamic_impl<S: Spec, W: fmt::Write, C: DynamicContext>(
- template: &UriTemplateStr,
- writer: &mut W,
- context: &mut C,
-) -> Result<(), Error> {
- let mut pos = 0;
- for chunk in Chunks::new(template) {
- let expr = match chunk {
- Chunk::Literal(lit) => {
- writer
- .write_str(lit)
- .map_err(|_| Error::new(ErrorKind::WriteFailed, pos))?;
- pos += lit.len();
- continue;
- }
- Chunk::Expr(body) => body,
- };
- expand_expr_mut::<S, _, _>(writer, &mut pos, expr, context)?;
- }
-
- Ok(())
-}
-
-/// Expands the expression using the given operator and the dynamic context.
-fn expand_expr_mut<S: Spec, W: fmt::Write, C: DynamicContext>(
- writer: &mut W,
- pos: &mut usize,
- expr: ExprBody<'_>,
- context: &mut C,
-) -> Result<(), Error> {
- let (op, varlist) = expr.decompose();
-
- let mut is_first_varspec = true;
- // +2: wrapping braces (`{` and `}`).
- let chunk_end_pos = *pos + expr.as_str().len() + 2;
- // +1: opening brace `{`.
- *pos += op.len() + 1;
- for (varspec_len, varspec) in varlist {
- // Check the type before the actual expansion.
- let ty = context.visit_dynamic(TypeVisitor::new(varspec.name()));
- let modifier = varspec.modifier();
-
- if matches!(modifier, Modifier::MaxLen(_))
- && matches!(ty, ValueType::List | ValueType::Assoc)
- {
- // > Prefix modifiers are not applicable to variables that
- // > have composite values.
- //
- // --- [RFC 6570 Section 2.4.1. Prefix](https://www.rfc-editor.org/rfc/rfc6570.html#section-2.4.1)
- return Err(Error::new(ErrorKind::UnexpectedValueType, *pos));
- }
-
- // Typecheck passed. Expand.
- let visitor = ValueVisitor::<S, _>::new(writer, varspec, op, &mut is_first_varspec);
- let token = context
- .visit_dynamic(visitor)
- .map_err(|_| Error::new(ErrorKind::WriteFailed, *pos))?;
- let writer_ptr = token.writer_ptr();
- if writer_ptr != writer as *mut _ {
- // Invalid `VisitDoneToken` was returned. This cannot usually happen
- // without intentional unnatural usage.
- panic!("invalid `VisitDoneToken` was returned");
- }
-
- // +1: A trailing comman (`,`) or a closing brace (`}`).
- *pos += varspec_len + 1;
- }
- assert_eq!(*pos, chunk_end_pos);
-
- Ok(())
-}
-
-/// Properties of an operator.
-///
-/// See [RFC 6570 Appendix A](https://www.rfc-editor.org/rfc/rfc6570#appendix-A).
-#[derive(Debug, Clone, Copy)]
-struct OpProps {
- /// Prefix for the first element.
- first: &'static str,
- /// Separator.
- sep: &'static str,
- /// Whether or not the expansion includes the variable or key name.
- named: bool,
- /// Result string if the variable is empty.
- ifemp: &'static str,
- /// Whether or not the reserved values can be written without being encoded.
- allow_reserved: bool,
-}
-
-impl OpProps {
- /// Properties for all known operators.
- const PROPS: [Self; 8] = [
- // String
- Self {
- first: "",
- sep: ",",
- named: false,
- ifemp: "",
- allow_reserved: false,
- },
- // Reserved
- Self {
- first: "",
- sep: ",",
- named: false,
- ifemp: "",
- allow_reserved: true,
- },
- // Fragment
- Self {
- first: "#",
- sep: ",",
- named: false,
- ifemp: "",
- allow_reserved: true,
- },
- // Label
- Self {
- first: ".",
- sep: ".",
- named: false,
- ifemp: "",
- allow_reserved: false,
- },
- // PathSegments
- Self {
- first: "/",
- sep: "/",
- named: false,
- ifemp: "",
- allow_reserved: false,
- },
- // PathParams
- Self {
- first: ";",
- sep: ";",
- named: true,
- ifemp: "",
- allow_reserved: false,
- },
- // FormQuery
- Self {
- first: "?",
- sep: "&",
- named: true,
- ifemp: "=",
- allow_reserved: false,
- },
- // FormQueryCont
- Self {
- first: "&",
- sep: "&",
- named: true,
- ifemp: "=",
- allow_reserved: false,
- },
- ];
-
- /// Returns the properties for the operator.
- #[must_use]
- #[inline]
- pub(super) fn from_op(op: Operator) -> &'static Self {
- let index = match op {
- Operator::String => 0,
- Operator::Reserved => 1,
- Operator::Fragment => 2,
- Operator::Label => 3,
- Operator::PathSegments => 4,
- Operator::PathParams => 5,
- Operator::FormQuery => 6,
- Operator::FormQueryCont => 7,
- };
- &Self::PROPS[index]
- }
-}
-
-/// Expands the expression using the given operator.
-fn expand<S: Spec, C: Context>(
- f: &mut fmt::Formatter<'_>,
- expr: ExprBody<'_>,
- context: &C,
-) -> fmt::Result {
- let (op, varlist) = expr.decompose();
-
- let mut is_first_varspec = true;
- for (_varspec_len, varspec) in varlist {
- let visitor = ValueVisitor::<S, _>::new(f, varspec, op, &mut is_first_varspec);
- let token = context.visit(visitor)?;
- let writer_ptr = token.writer_ptr();
- if writer_ptr != f as *mut _ {
- // Invalid `VisitDoneToken` was returned. This cannot usually happen
- // without intentional unnatural usage.
- panic!("invalid `VisitDoneToken` was returned");
- }
- }
-
- Ok(())
-}
-
-/// Escapes the given value and writes it.
-#[inline]
-fn escape_write<S: Spec, T: fmt::Display, W: fmt::Write>(
- f: &mut W,
- v: T,
- allow_reserved: bool,
-) -> fmt::Result {
- if allow_reserved {
- let result = process_percent_encoded_best_effort(v, |frag| {
- let result = match frag {
- PctEncodedFragments::Char(s, _) => f.write_str(s),
- PctEncodedFragments::NoPctStr(s) => {
- write!(f, "{}", PercentEncoded::<_, S>::characters(s))
- }
- PctEncodedFragments::StrayPercent => f.write_str("%25"),
- PctEncodedFragments::InvalidUtf8PctTriplets(s) => f.write_str(s),
- };
- if result.is_err() {
- return ControlFlow::Break(result);
- }
- ControlFlow::Continue(())
- });
- match result {
- Ok(ControlFlow::Break(Ok(_)) | ControlFlow::Continue(_)) => Ok(()),
- Ok(ControlFlow::Break(Err(e))) | Err(e) => Err(e),
- }
- } else {
- /// Writer that escapes the unreserved characters and writes them.
- struct UnreservePercentEncodeWriter<'a, S, W> {
- /// Inner writer.
- writer: &'a mut W,
- /// Spec.
- _spec: PhantomData<fn() -> S>,
- }
- impl<S: Spec, W: fmt::Write> fmt::Write for UnreservePercentEncodeWriter<'_, S, W> {
- #[inline]
- fn write_str(&mut self, s: &str) -> fmt::Result {
- write!(self.writer, "{}", PercentEncoded::<_, S>::unreserve(s))
- }
- }
- let mut writer = UnreservePercentEncodeWriter::<S, W> {
- writer: f,
- _spec: PhantomData,
- };
- write!(writer, "{v}")
- }
-}
-
-/// Truncates the given value as a string, escapes the value, and writes it.
-fn escape_write_with_maxlen<S: Spec, T: fmt::Display, W: fmt::Write>(
- writer: &mut PrefixOnceWriter<'_, W>,
- v: T,
- allow_reserved: bool,
- max_len: Option<u16>,
-) -> fmt::Result {
- if allow_reserved {
- let mut max_len = max_len.map_or(usize::MAX, usize::from);
- let result = process_percent_encoded_best_effort(v, |frag| {
- if max_len == 0 {
- return ControlFlow::Break(Ok(()));
- }
- let result =
- match frag {
- PctEncodedFragments::Char(s, _) => {
- max_len -= 1;
- writer.write_str(s)
- }
- PctEncodedFragments::NoPctStr(s) => {
- let mut chars = s.char_indices();
- let count =
- chars.by_ref().take(max_len).last().map(|(i, _)| i).expect(
- "[consistency] decomposed string fragment must not be empty",
- );
- let sub_len = s.len() - chars.as_str().len();
- max_len -= count;
- write!(
- writer,
- "{}",
- PercentEncoded::<_, S>::characters(&s[..sub_len])
- )
- }
- PctEncodedFragments::StrayPercent => {
- max_len -= 1;
- writer.write_str("%25")
- }
- PctEncodedFragments::InvalidUtf8PctTriplets(s) => {
- let count = max_len.min(s.len() / 3);
- let sub_len = count * 3;
- max_len -= count;
- writer.write_str(&s[..sub_len])
- }
- };
- if result.is_err() {
- return ControlFlow::Break(result);
- }
- ControlFlow::Continue(())
- });
- match result {
- Ok(ControlFlow::Break(Ok(_)) | ControlFlow::Continue(_)) => Ok(()),
- Ok(ControlFlow::Break(Err(e))) | Err(e) => Err(e),
- }
- } else {
- match max_len {
- Some(max_len) => {
- let mut writer = TruncatePercentEncodeWriter::<S, _> {
- inner: writer,
- rest_num_chars: usize::from(max_len),
- _spec: PhantomData,
- };
- write!(writer, "{v}")
- }
- None => write!(writer, "{}", PercentEncoded::<_, S>::unreserve(v)),
- }
- }
-}
-
-/// A writer that truncates the input to the given length and writes to the backend.
-struct TruncatePercentEncodeWriter<'a, S, W> {
- /// Inner writer.
- inner: &'a mut W,
- /// Maximum number of characters to be written.
- rest_num_chars: usize,
- /// Spec.
- _spec: PhantomData<fn() -> S>,
-}
-
-impl<S: Spec, W: fmt::Write> fmt::Write for TruncatePercentEncodeWriter<'_, S, W> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- if self.rest_num_chars == 0 {
- return Ok(());
- }
- let mut chars = s.char_indices();
- let skip_count = chars
- .by_ref()
- .take(self.rest_num_chars)
- .last()
- .map_or(0, |(i, _)| i + 1);
- let len = s.len() - chars.as_str().len();
- let truncated = &s[..len];
- write!(
- self.inner,
- "{}",
- PercentEncoded::<_, S>::unreserve(truncated)
- )?;
- self.rest_num_chars -= skip_count;
- Ok(())
- }
-}
-
-/// A writer that writes a prefix only once if and only if some value is written.
-struct PrefixOnceWriter<'a, W> {
- /// Inner writer.
- inner: &'a mut W,
- /// Prefix to write.
- prefix: Option<&'a str>,
-}
-
-impl<'a, W: fmt::Write> PrefixOnceWriter<'a, W> {
- /// Creates a new writer with no prefix.
- #[inline]
- #[must_use]
- fn new(inner: &'a mut W) -> Self {
- Self {
- inner,
- prefix: None,
- }
- }
-
- /// Creates a new writer with a prefix.
- #[inline]
- #[must_use]
- fn with_prefix(inner: &'a mut W, prefix: &'a str) -> Self {
- Self {
- inner,
- prefix: Some(prefix),
- }
- }
-
- /// Returns true if the writer have not yet written the prefix.
- #[inline]
- #[must_use]
- fn has_unwritten_prefix(&self) -> bool {
- self.prefix.is_some()
- }
-}
-
-impl<W: fmt::Write> fmt::Write for PrefixOnceWriter<'_, W> {
- #[inline]
- fn write_str(&mut self, s: &str) -> fmt::Result {
- if let Some(prefix) = self.prefix.take() {
- self.inner.write_str(prefix)?;
- }
- self.inner.write_str(s)
- }
-}
-
-/// An opaque token value that proves some variable is visited.
-// This should not be able to be created by any means other than `VarVisitor::visit_foo()`.
-// Do not derive any traits that allows the value to be generated or cloned.
-struct VisitDoneToken<'a, S, W>(ValueVisitor<'a, S, W>);
-
-impl<'a, S: Spec, W: fmt::Write> VisitDoneToken<'a, S, W> {
- /// Creates a new token.
- #[inline]
- #[must_use]
- fn new(visitor: ValueVisitor<'a, S, W>) -> Self {
- Self(visitor)
- }
-
- /// Returns the raw pointer to the backend formatter.
- #[inline]
- #[must_use]
- fn writer_ptr(&self) -> *const W {
- self.0.writer_ptr()
- }
-}
-
-impl<S: Spec, W: fmt::Write> fmt::Debug for VisitDoneToken<'_, S, W> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("VisitDoneToken")
- }
-}
-
-/// Visitor to retrieve a variable value.
-// Single `ValueVisitor` should be used for single expansion.
-// Do not derive any traits that allows the value to be generated or cloned.
-struct ValueVisitor<'a, S, W> {
- /// Formatter.
- writer: &'a mut W,
- /// Varspec.
- varspec: VarSpec<'a>,
- /// Operator.
- op: Operator,
- /// Whether the variable to visit is the first one in an expression.
- is_first_varspec: &'a mut bool,
- /// Spec.
- _spec: PhantomData<fn() -> S>,
-}
-
-impl<'a, S: Spec, W: fmt::Write> ValueVisitor<'a, S, W> {
- /// Creates a visitor.
- #[inline]
- #[must_use]
- fn new(
- f: &'a mut W,
- varspec: VarSpec<'a>,
- op: Operator,
- is_first_varspec: &'a mut bool,
- ) -> Self {
- Self {
- writer: f,
- varspec,
- op,
- is_first_varspec,
- _spec: PhantomData,
- }
- }
-
- /// Returns the raw pointer to the backend formatter.
- #[inline]
- #[must_use]
- fn writer_ptr(&self) -> *const W {
- self.writer as &_ as *const _
- }
-}
-
-impl<S: Spec, W: fmt::Write> VisitorSealed for ValueVisitor<'_, S, W> {}
-
-impl<'a, S: Spec, W: fmt::Write> Visitor for ValueVisitor<'a, S, W> {
- type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
- type ListVisitor = ListValueVisitor<'a, S, W>;
- type AssocVisitor = AssocValueVisitor<'a, S, W>;
-
- /// Returns the name of the variable to visit.
- #[inline]
- #[must_use]
- fn var_name(&self) -> VarName<'a> {
- self.varspec.name()
- }
-
- #[inline]
- fn purpose(&self) -> VisitPurpose {
- VisitPurpose::Expand
- }
-
- /// Visits an undefined variable, i.e. indicates that the requested variable is unavailable.
- #[inline]
- fn visit_undefined(self) -> Self::Result {
- Ok(VisitDoneToken::new(self))
- }
-
- /// Visits a string variable.
- #[inline]
- fn visit_string<T: fmt::Display>(self, v: T) -> Self::Result {
- let oppr = OpProps::from_op(self.op);
-
- if mem::replace(self.is_first_varspec, false) {
- self.writer.write_str(oppr.first)?;
- } else {
- self.writer.write_str(oppr.sep)?;
- }
- let mut writer = if oppr.named {
- self.writer.write_str(self.varspec.name().as_str())?;
- PrefixOnceWriter::with_prefix(self.writer, "=")
- } else {
- PrefixOnceWriter::new(self.writer)
- };
-
- let max_len = match self.varspec.modifier() {
- Modifier::None | Modifier::Explode => None,
- Modifier::MaxLen(max_len) => Some(max_len),
- };
- escape_write_with_maxlen::<S, T, W>(&mut writer, v, oppr.allow_reserved, max_len)?;
- if writer.has_unwritten_prefix() {
- self.writer.write_str(oppr.ifemp)?;
- }
- Ok(VisitDoneToken::new(self))
- }
-
- /// Visits a list variable.
- #[inline]
- #[must_use]
- fn visit_list(self) -> Self::ListVisitor {
- let oppr = OpProps::from_op(self.op);
- ListValueVisitor {
- visitor: self,
- num_elems: 0,
- oppr,
- }
- }
-
- /// Visits an associative array variable.
- #[inline]
- #[must_use]
- fn visit_assoc(self) -> Self::AssocVisitor {
- let oppr = OpProps::from_op(self.op);
- AssocValueVisitor {
- visitor: self,
- num_elems: 0,
- oppr,
- }
- }
-}
-
-/// Visitor to retrieve value of a list variable.
-// RFC 6570 section 2.3:
-//
-// > A variable defined as a list value is considered undefined if the
-// > list contains zero members. A variable defined as an associative
-// > array of (name, value) pairs is considered undefined if the array
-// > contains zero members or if all member names in the array are
-// > associated with undefined values.
-//
-// Single variable visitor should be used for single expansion.
-// Do not derive any traits that allows the value to be generated or cloned.
-struct ListValueVisitor<'a, S, W> {
- /// Visitor.
- visitor: ValueVisitor<'a, S, W>,
- /// Number of already emitted elements.
- num_elems: usize,
- /// Operator props.
- oppr: &'static OpProps,
-}
-
-impl<S: Spec, W: fmt::Write> ListValueVisitor<'_, S, W> {
- /// Visits an item.
- fn visit_item_impl<T: fmt::Display>(&mut self, item: T) -> fmt::Result {
- let modifier = self.visitor.varspec.modifier();
- let is_explode = match modifier {
- Modifier::MaxLen(_) => panic!(
- "value type changed since `UriTemplateStr::expand()`: \
- prefix modifier is not applicable to a list"
- ),
- Modifier::None => false,
- Modifier::Explode => true,
- };
-
- // Write prefix for each variable.
- if self.num_elems == 0 {
- if mem::replace(self.visitor.is_first_varspec, false) {
- self.visitor.writer.write_str(self.oppr.first)?;
- } else {
- self.visitor.writer.write_str(self.oppr.sep)?;
- }
- if self.oppr.named {
- self.visitor
- .writer
- .write_str(self.visitor.varspec.name().as_str())?;
- self.visitor.writer.write_char('=')?;
- }
- } else {
- // Write prefix for the non-first item.
- match (self.oppr.named, is_explode) {
- (_, false) => self.visitor.writer.write_char(',')?,
- (false, true) => self.visitor.writer.write_str(self.oppr.sep)?,
- (true, true) => {
- self.visitor.writer.write_str(self.oppr.sep)?;
- escape_write::<S, _, _>(
- self.visitor.writer,
- self.visitor.varspec.name().as_str(),
- self.oppr.allow_reserved,
- )?;
- self.visitor.writer.write_char('=')?;
- }
- }
- }
-
- escape_write::<S, _, _>(self.visitor.writer, item, self.oppr.allow_reserved)?;
-
- self.num_elems += 1;
- Ok(())
- }
-}
-
-impl<S: Spec, W: fmt::Write> VisitorSealed for ListValueVisitor<'_, S, W> {}
-
-impl<'a, S: Spec, W: fmt::Write> ListVisitor for ListValueVisitor<'a, S, W> {
- type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
-
- /// Visits an item.
- #[inline]
- fn visit_item<T: fmt::Display>(&mut self, item: T) -> ControlFlow<Self::Result> {
- match self.visit_item_impl(item) {
- Ok(_) => ControlFlow::Continue(()),
- Err(e) => ControlFlow::Break(Err(e)),
- }
- }
-
- /// Finishes visiting the list.
- #[inline]
- fn finish(self) -> Self::Result {
- Ok(VisitDoneToken::new(self.visitor))
- }
-}
-
-/// Visitor to retrieve entries of an associative array variable.
-// RFC 6570 section 2.3:
-//
-// > A variable defined as a list value is considered undefined if the
-// > list contains zero members. A variable defined as an associative
-// > array of (name, value) pairs is considered undefined if the array
-// > contains zero members or if all member names in the array are
-// > associated with undefined values.
-//
-// Single variable visitor should be used for single expansion.
-// Do not derive any traits that allows the value to be generated or cloned.
-struct AssocValueVisitor<'a, S, W> {
- /// Visitor.
- visitor: ValueVisitor<'a, S, W>,
- /// Number of already emitted elements.
- num_elems: usize,
- /// Operator props.
- oppr: &'static OpProps,
-}
-
-impl<S: Spec, W: fmt::Write> AssocValueVisitor<'_, S, W> {
- /// Visits an entry.
- fn visit_entry_impl<K: fmt::Display, V: fmt::Display>(
- &mut self,
- key: K,
- value: V,
- ) -> fmt::Result {
- let modifier = self.visitor.varspec.modifier();
- let is_explode = match modifier {
- Modifier::MaxLen(_) => panic!(
- "value type changed since `UriTemplateStr::expand()`: \
- prefix modifier is not applicable to an associative array"
- ),
- Modifier::None => false,
- Modifier::Explode => true,
- };
-
- // Write prefix for each variable.
- if self.num_elems == 0 {
- if mem::replace(self.visitor.is_first_varspec, false) {
- self.visitor.writer.write_str(self.oppr.first)?;
- } else {
- self.visitor.writer.write_str(self.oppr.sep)?;
- }
- if is_explode {
- escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
- self.visitor.writer.write_char('=')?;
- } else {
- if self.oppr.named {
- escape_write::<S, _, _>(
- self.visitor.writer,
- self.visitor.varspec.name().as_str(),
- self.oppr.allow_reserved,
- )?;
- self.visitor.writer.write_char('=')?;
- }
- escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
- self.visitor.writer.write_char(',')?;
- }
- } else {
- // Write prefix for the non-first item.
- match (self.oppr.named, is_explode) {
- (_, false) => {
- self.visitor.writer.write_char(',')?;
- escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
- self.visitor.writer.write_char(',')?;
- }
- (false, true) => {
- self.visitor.writer.write_str(self.oppr.sep)?;
- escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
- self.visitor.writer.write_char('=')?;
- }
- (true, true) => {
- self.visitor.writer.write_str(self.oppr.sep)?;
- escape_write::<S, _, _>(self.visitor.writer, key, self.oppr.allow_reserved)?;
- self.visitor.writer.write_char('=')?;
- }
- }
- }
-
- escape_write::<S, _, _>(self.visitor.writer, value, self.oppr.allow_reserved)?;
-
- self.num_elems += 1;
- Ok(())
- }
-}
-
-impl<S: Spec, W: fmt::Write> VisitorSealed for AssocValueVisitor<'_, S, W> {}
-
-impl<'a, S: Spec, W: fmt::Write> AssocVisitor for AssocValueVisitor<'a, S, W> {
- type Result = Result<VisitDoneToken<'a, S, W>, fmt::Error>;
-
- /// Visits an entry.
- #[inline]
- fn visit_entry<K: fmt::Display, V: fmt::Display>(
- &mut self,
- key: K,
- value: V,
- ) -> ControlFlow<Self::Result> {
- match self.visit_entry_impl(key, value) {
- Ok(_) => ControlFlow::Continue(()),
- Err(e) => ControlFlow::Break(Err(e)),
- }
- }
-
- /// Finishes visiting the associative array.
- #[inline]
- fn finish(self) -> Self::Result {
- Ok(VisitDoneToken::new(self.visitor))
- }
-}
-
-/// Visitor to retrieve effective type of a variable.
-struct TypeVisitor<'a> {
- /// Variable name.
- var_name: VarName<'a>,
-}
-
-impl<'a> TypeVisitor<'a> {
- /// Creates a new type visitor.
- #[inline]
- #[must_use]
- fn new(var_name: VarName<'a>) -> Self {
- Self { var_name }
- }
-}
-
-impl VisitorSealed for TypeVisitor<'_> {}
-
-impl<'a> Visitor for TypeVisitor<'a> {
- type Result = ValueType;
- type ListVisitor = ListTypeVisitor;
- type AssocVisitor = AssocTypeVisitor;
-
- #[inline]
- fn var_name(&self) -> VarName<'a> {
- self.var_name
- }
- #[inline]
- fn purpose(&self) -> VisitPurpose {
- VisitPurpose::Typecheck
- }
- #[inline]
- fn visit_undefined(self) -> Self::Result {
- ValueType::undefined()
- }
- #[inline]
- fn visit_string<T: fmt::Display>(self, _: T) -> Self::Result {
- ValueType::string()
- }
- #[inline]
- fn visit_list(self) -> Self::ListVisitor {
- ListTypeVisitor
- }
- #[inline]
- fn visit_assoc(self) -> Self::AssocVisitor {
- AssocTypeVisitor
- }
-}
-
-/// Visitor to retrieve effective type of a list variable.
-struct ListTypeVisitor;
-
-impl VisitorSealed for ListTypeVisitor {}
-
-impl ListVisitor for ListTypeVisitor {
- type Result = ValueType;
-
- /// Visits an item.
- #[inline]
- fn visit_item<T: fmt::Display>(&mut self, _item: T) -> ControlFlow<Self::Result> {
- ControlFlow::Break(ValueType::nonempty_list())
- }
-
- /// Finishes visiting the list.
- #[inline]
- fn finish(self) -> Self::Result {
- ValueType::empty_list()
- }
-}
-
-/// Visitor to retrieve effective type of an associative array variable.
-struct AssocTypeVisitor;
-
-impl VisitorSealed for AssocTypeVisitor {}
-
-impl AssocVisitor for AssocTypeVisitor {
- type Result = ValueType;
-
- /// Visits an item.
- #[inline]
- fn visit_entry<K: fmt::Display, V: fmt::Display>(
- &mut self,
- _key: K,
- _value: V,
- ) -> ControlFlow<Self::Result> {
- ControlFlow::Break(ValueType::nonempty_assoc())
- }
-
- /// Finishes visiting the list.
- #[inline]
- fn finish(self) -> Self::Result {
- ValueType::empty_assoc()
- }
-}
diff --git a/vendor/iri-string/src/template/parser.rs b/vendor/iri-string/src/template/parser.rs
deleted file mode 100644
index 6d5443a8..00000000
--- a/vendor/iri-string/src/template/parser.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! URI Template parser.
-
-pub(super) mod char;
-pub(super) mod validate;
-
-pub(super) use self::validate::validate_template_str;
diff --git a/vendor/iri-string/src/template/parser/char.rs b/vendor/iri-string/src/template/parser/char.rs
deleted file mode 100644
index 9ad4a6d8..00000000
--- a/vendor/iri-string/src/template/parser/char.rs
+++ /dev/null
@@ -1,190 +0,0 @@
-//! Characters.
-
-/// Properties of ASCII characters.
-///
-/// About `'` (single quote) being considered as a literal: see
-/// [Errata ID 6937](https://www.rfc-editor.org/errata/eid6937).
-const CHARS_TABLE: [u8; 128] = [
- 0b_0000_0000, // NUL
- 0b_0000_0000, // SOH
- 0b_0000_0000, // STX
- 0b_0000_0000, // ETX
- 0b_0000_0000, // EOT
- 0b_0000_0000, // ENQ
- 0b_0000_0000, // ACK
- 0b_0000_0000, // BEL
- 0b_0000_0000, // BS
- 0b_0000_0000, // HT
- 0b_0000_0000, // LF
- 0b_0000_0000, // VT
- 0b_0000_0000, // FF
- 0b_0000_0000, // CR
- 0b_0000_0000, // SO
- 0b_0000_0000, // SI
- 0b_0000_0000, // DLE
- 0b_0000_0000, // DC1
- 0b_0000_0000, // DC2
- 0b_0000_0000, // DC3
- 0b_0000_0000, // DC4
- 0b_0000_0000, // NAK
- 0b_0000_0000, // SYN
- 0b_0000_0000, // ETB
- 0b_0000_0000, // CAN
- 0b_0000_0000, // EM
- 0b_0000_0000, // SUB
- 0b_0000_0000, // ESC
- 0b_0000_0000, // FS
- 0b_0000_0000, // GS
- 0b_0000_0000, // RS
- 0b_0000_0000, // US
- 0b_0000_0000, // SPACE
- 0b_0000_0001, // !
- 0b_0000_0000, // "
- 0b_0000_0001, // #
- 0b_0000_0001, // $
- 0b_0000_0000, // %
- 0b_0000_0001, // &
- 0b_0000_0001, // '
- 0b_0000_0001, // (
- 0b_0000_0001, // )
- 0b_0000_0001, // *
- 0b_0000_0001, // +
- 0b_0000_0001, // ,
- 0b_0000_0001, // -
- 0b_0000_0101, // .
- 0b_0000_0001, // /
- 0b_0000_0111, // 0
- 0b_0000_0111, // 1
- 0b_0000_0111, // 2
- 0b_0000_0111, // 3
- 0b_0000_0111, // 4
- 0b_0000_0111, // 5
- 0b_0000_0111, // 6
- 0b_0000_0111, // 7
- 0b_0000_0111, // 8
- 0b_0000_0111, // 9
- 0b_0000_0001, // :
- 0b_0000_0001, // ;
- 0b_0000_0000, // <
- 0b_0000_0001, // =
- 0b_0000_0000, // >
- 0b_0000_0001, // ?
- 0b_0000_0001, // @
- 0b_0000_0111, // A
- 0b_0000_0111, // B
- 0b_0000_0111, // C
- 0b_0000_0111, // D
- 0b_0000_0111, // E
- 0b_0000_0111, // F
- 0b_0000_0111, // G
- 0b_0000_0111, // H
- 0b_0000_0111, // I
- 0b_0000_0111, // J
- 0b_0000_0111, // K
- 0b_0000_0111, // L
- 0b_0000_0111, // M
- 0b_0000_0111, // N
- 0b_0000_0111, // O
- 0b_0000_0111, // P
- 0b_0000_0111, // Q
- 0b_0000_0111, // R
- 0b_0000_0111, // S
- 0b_0000_0111, // T
- 0b_0000_0111, // U
- 0b_0000_0111, // V
- 0b_0000_0111, // W
- 0b_0000_0111, // X
- 0b_0000_0111, // Y
- 0b_0000_0111, // Z
- 0b_0000_0001, // [
- 0b_0000_0000, // \
- 0b_0000_0001, // ]
- 0b_0000_0000, // ^
- 0b_0000_0111, // _
- 0b_0000_0000, // `
- 0b_0000_0111, // a
- 0b_0000_0111, // b
- 0b_0000_0111, // c
- 0b_0000_0111, // d
- 0b_0000_0111, // e
- 0b_0000_0111, // f
- 0b_0000_0111, // g
- 0b_0000_0111, // h
- 0b_0000_0111, // i
- 0b_0000_0111, // j
- 0b_0000_0111, // k
- 0b_0000_0111, // l
- 0b_0000_0111, // m
- 0b_0000_0111, // n
- 0b_0000_0111, // o
- 0b_0000_0111, // p
- 0b_0000_0111, // q
- 0b_0000_0111, // r
- 0b_0000_0111, // s
- 0b_0000_0111, // t
- 0b_0000_0111, // u
- 0b_0000_0111, // v
- 0b_0000_0111, // w
- 0b_0000_0111, // x
- 0b_0000_0111, // y
- 0b_0000_0111, // z
- 0b_0000_0000, // {
- 0b_0000_0000, // |
- 0b_0000_0000, // }
- 0b_0000_0001, // ~
- 0b_0000_0000, // DEL
-];
-
-/// A mask to test whether the character matches `literals` rule defined in [RFC 6570].
-///
-/// [RFC 6570]: https://www.rfc-editor.org/rfc/rfc6570.html#section-2.1
-const CHARS_TABLE_MASK_LITERAL: u8 = 1 << 0;
-
-/// A mask to test whether the character matches `varchar` rule defined in [RFC 6570].
-///
-/// [RFC 6570]: https://www.rfc-editor.org/rfc/rfc6570.html#section-2.3
-const CHARS_TABLE_MASK_VARCHAR_START: u8 = 1 << 1;
-
-/// A mask to test whether the character matches `varchar` rule defined in [RFC 6570] or a period.
-///
-/// [RFC 6570]: https://www.rfc-editor.org/rfc/rfc6570.html#section-2.3
-const CHARS_TABLE_MASK_VARCHAR_CONTINUE: u8 = 1 << 2;
-
-/// Returns true if the given ASCII character is allowed in a literal string.
-///
-/// # Precondition
-///
-/// The given byte should be an ASCII character, i.e. should be less than 128.
-#[inline]
-#[must_use]
-pub(super) const fn is_ascii_literal_char(c: u8) -> bool {
- (CHARS_TABLE[c as usize] & CHARS_TABLE_MASK_LITERAL) != 0
-}
-
-/// Returns true if the given ASCII character is allowed as the beginning of the `varname`.
-///
-/// Note that this does not return true for `%` character. It is caller's
-/// responsibility to test validity of percent-encoded triplets.
-///
-/// # Precondition
-///
-/// The given byte should be an ASCII character, i.e. should be less than 128.
-#[inline]
-#[must_use]
-pub(super) const fn is_ascii_varchar_start(c: u8) -> bool {
- (CHARS_TABLE[c as usize] & CHARS_TABLE_MASK_VARCHAR_START) != 0
-}
-
-/// Returns true if the given ASCII character is allowed as the non-beginning of the `varname`.
-///
-/// Note that this does not return true for `%` character. It is caller's
-/// responsibility to test validity of percent-encoded triplets.
-///
-/// # Precondition
-///
-/// The given byte should be an ASCII character, i.e. should be less than 128.
-#[inline]
-#[must_use]
-pub(super) const fn is_ascii_varchar_continue(c: u8) -> bool {
- (CHARS_TABLE[c as usize] & CHARS_TABLE_MASK_VARCHAR_CONTINUE) != 0
-}
diff --git a/vendor/iri-string/src/template/parser/validate.rs b/vendor/iri-string/src/template/parser/validate.rs
deleted file mode 100644
index 67ab6c01..00000000
--- a/vendor/iri-string/src/template/parser/validate.rs
+++ /dev/null
@@ -1,161 +0,0 @@
-//! Validating parsers.
-
-use crate::parser::str::{
- find_split2_hole, find_split_hole, satisfy_chars_with_pct_encoded, starts_with_double_hexdigits,
-};
-use crate::template::components::MaybeOperator;
-use crate::template::error::{Error, ErrorKind};
-
-use crate::template::parser::char::{
- is_ascii_literal_char, is_ascii_varchar_continue, is_ascii_varchar_start,
-};
-
-/// Returns `Ok(())` if the given string is a valid literal.
-fn validate_literal(s: &str, offset: usize) -> Result<(), Error> {
- match s
- .chars()
- .position(|c| !c.is_ascii() || !is_ascii_literal_char(c as u8))
- {
- Some(pos) => Err(Error::new(ErrorKind::InvalidCharacter, offset + pos)),
- None => Ok(()),
- }
-}
-
-/// Returns `Ok(())` if the given string is a valid varspec.
-fn validate_varspec(s: &str, offset: usize) -> Result<(), Error> {
- match find_split2_hole(s, b':', b'*') {
- Some((maybe_varname, b':', maybe_len)) => {
- validate_varname(maybe_varname, offset)?;
- if !(1..=5).contains(&maybe_len.len()) {
- return Err(Error::new(
- ErrorKind::InvalidExpression,
- offset + maybe_varname.len() + 2,
- ));
- }
- if let Some(pos) = maybe_len.bytes().position(|b| !b.is_ascii_digit()) {
- return Err(Error::new(
- ErrorKind::InvalidExpression,
- offset + maybe_varname.len() + 2 + pos,
- ));
- }
- }
- Some((maybe_varname, b'*', extra)) => {
- validate_varname(maybe_varname, offset)?;
- if !extra.is_empty() {
- return Err(Error::new(
- ErrorKind::InvalidExpression,
- offset + maybe_varname.len() + 1,
- ));
- }
- }
- Some((_, sep, _)) => unreachable!("[consistency] the byte {sep:#02x} is not searched"),
- None => validate_varname(s, offset)?,
- }
- Ok(())
-}
-
-/// Returns `Ok(())` if the given string is a valid varname.
-pub(crate) fn validate_varname(s: &str, offset: usize) -> Result<(), Error> {
- let rest = match s.as_bytes().first() {
- Some(b'%') if starts_with_double_hexdigits(&s.as_bytes()[1..]) => &s[3..],
- Some(b) if b.is_ascii() && is_ascii_varchar_start(*b) => &s[1..],
- _ => return Err(Error::new(ErrorKind::InvalidExpression, offset)),
- };
- let is_valid = satisfy_chars_with_pct_encoded(rest, is_ascii_varchar_continue, |_| false);
- if !is_valid {
- return Err(Error::new(ErrorKind::InvalidExpression, offset));
- }
- Ok(())
-}
-
-/// Returns `Ok(())` if the given string is a valid expression.
-///
-/// "Expression" here is the expression body inside `{` and `}`, but not including braces.
-fn validate_expr_body(s: &str, mut offset: usize) -> Result<(), Error> {
- if s.is_empty() {
- return Err(Error::new(ErrorKind::InvalidExpression, offset));
- }
-
- // Skip the operator.
- let maybe_variable_list = match MaybeOperator::from_byte(s.as_bytes()[0]) {
- Some(MaybeOperator::Operator(_)) => {
- offset += 1;
- &s[1..]
- }
- Some(MaybeOperator::Reserved(_)) => {
- return Err(Error::new(ErrorKind::UnsupportedOperator, offset));
- }
- None => s,
- };
-
- // Validate varspecs.
- for (spec_i, maybe_varspec) in maybe_variable_list.split(',').enumerate() {
- if spec_i != 0 {
- // Add the length of the leading separator `,`.
- offset += 1;
- }
- validate_varspec(maybe_varspec, offset)?;
- offset += maybe_varspec.len();
- }
-
- Ok(())
-}
-
-/// Validates whether the given string is valid as a URI template.
-///
-/// Returns `Ok(())` if the given string is a valid URI template.
-pub(in crate::template) fn validate_template_str(s: &str) -> Result<(), Error> {
- let mut rest = s;
- let mut offset = 0;
- while !rest.is_empty() {
- rest = match find_split2_hole(rest, b'%', b'{') {
- Some((literal, b'%', xdigits2_and_rest)) => {
- validate_literal(literal, offset)?;
-
- if xdigits2_and_rest.len() < 2 {
- return Err(Error::new(
- ErrorKind::InvalidPercentEncoding,
- offset + literal.len(),
- ));
- }
- let (xdigits2, new_rest) = xdigits2_and_rest.split_at(2);
- if !xdigits2.as_bytes()[0].is_ascii_hexdigit() {
- return Err(Error::new(
- ErrorKind::InvalidPercentEncoding,
- offset + literal.len() + 1,
- ));
- }
- if !xdigits2.as_bytes()[1].is_ascii_hexdigit() {
- return Err(Error::new(
- ErrorKind::InvalidPercentEncoding,
- offset + literal.len() + 2,
- ));
- }
- new_rest
- }
- Some((literal, b'{', expr_and_rest)) => {
- validate_literal(literal, offset)?;
-
- let (expr, new_rest) = match find_split_hole(expr_and_rest, b'}') {
- Some(v) => v,
- None => {
- return Err(Error::new(
- ErrorKind::ExpressionNotClosed,
- offset + literal.len(),
- ))
- }
- };
-
- // +1 is `+ "{".len()`.
- validate_expr_body(expr, offset + literal.len() + 1)?;
-
- new_rest
- }
- Some(_) => unreachable!("[consistency] searching only `%` and `{{`"),
- None => return validate_literal(rest, offset),
- };
- offset = s.len() - rest.len();
- }
-
- Ok(())
-}
diff --git a/vendor/iri-string/src/template/simple_context.rs b/vendor/iri-string/src/template/simple_context.rs
deleted file mode 100644
index 5c19dc79..00000000
--- a/vendor/iri-string/src/template/simple_context.rs
+++ /dev/null
@@ -1,218 +0,0 @@
-//! Simple general-purpose context type.
-
-use core::ops::ControlFlow;
-
-use alloc::collections::BTreeMap;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::vec::Vec;
-
-use crate::template::context::{Context, VarName, Visitor};
-
-/// Value.
-#[derive(Debug, Clone)]
-pub enum Value {
- /// Undefined (i.e. null).
- Undefined,
- /// String value.
- String(String),
- /// List.
- List(Vec<String>),
- /// Associative array.
- Assoc(Vec<(String, String)>),
-}
-
-impl From<&str> for Value {
- #[inline]
- fn from(v: &str) -> Self {
- Self::String(v.into())
- }
-}
-
-impl From<String> for Value {
- #[inline]
- fn from(v: String) -> Self {
- Self::String(v)
- }
-}
-
-/// Simple template expansion context.
-#[derive(Default, Debug, Clone)]
-pub struct SimpleContext {
- /// Variable values.
- // Any map types (including `HashMap`) is ok, but the hash map is not provided by `alloc`.
- //
- // QUESTION: Should hexdigits in percent-encoded triplets in varnames be
- // compared case sensitively?
- variables: BTreeMap<String, Value>,
-}
-
-impl SimpleContext {
- /// Creates a new empty context.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::spec::UriSpec;
- /// use iri_string::template::UriTemplateStr;
- /// use iri_string::template::simple_context::SimpleContext;
- ///
- /// let empty_ctx = SimpleContext::new();
- /// let template = UriTemplateStr::new("{no_such_variable}")?;
- /// let expanded = template.expand::<UriSpec, _>(&empty_ctx)?;
- ///
- /// assert_eq!(
- /// expanded.to_string(),
- /// ""
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Inserts a variable.
- ///
- /// Passing [`Value::Undefined`] removes the value from the context.
- ///
- /// The entry will be inserted or removed even if the key is invalid as a
- /// variable name. Such entries will be simply ignored on expansion.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::spec::UriSpec;
- /// use iri_string::template::UriTemplateStr;
- /// use iri_string::template::simple_context::SimpleContext;
- ///
- /// let mut context = SimpleContext::new();
- /// context.insert("username", "foo");
- ///
- /// let template = UriTemplateStr::new("/users/{username}")?;
- /// let expanded = template.expand::<UriSpec, _>(&context)?;
- ///
- /// assert_eq!(
- /// expanded.to_string(),
- /// "/users/foo"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// Passing [`Value::Undefined`] removes the value from the context.
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// ## [cfg(feature = "alloc")] {
- /// use iri_string::spec::UriSpec;
- /// use iri_string::template::UriTemplateStr;
- /// use iri_string::template::simple_context::{SimpleContext, Value};
- ///
- /// let mut context = SimpleContext::new();
- /// context.insert("username", "foo");
- /// context.insert("username", Value::Undefined);
- ///
- /// let template = UriTemplateStr::new("/users/{username}")?;
- /// let expanded = template.expand::<UriSpec, _>(&context)?;
- ///
- /// assert_eq!(
- /// expanded.to_string(),
- /// "/users/"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn insert<K, V>(&mut self, key: K, value: V) -> Option<Value>
- where
- K: Into<String>,
- V: Into<Value>,
- {
- let key = key.into();
- match value.into() {
- Value::Undefined => self.variables.remove(&key),
- value => self.variables.insert(key, value),
- }
- }
-
- /// Removes all entries in the context.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::spec::UriSpec;
- /// use iri_string::template::UriTemplateStr;
- /// use iri_string::template::simple_context::SimpleContext;
- ///
- /// let template = UriTemplateStr::new("{foo,bar}")?;
- /// let mut context = SimpleContext::new();
- ///
- /// context.insert("foo", "FOO");
- /// context.insert("bar", "BAR");
- /// assert_eq!(
- /// template.expand::<UriSpec, _>(&context)?.to_string(),
- /// "FOO,BAR"
- /// );
- ///
- /// context.clear();
- /// assert_eq!(
- /// template.expand::<UriSpec, _>(&context)?.to_string(),
- /// ""
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn clear(&mut self) {
- self.variables.clear();
- }
-
- /// Returns a reference to the value for the key.
- //
- // QUESTION: Should hexdigits in percent-encoded triplets in varnames be
- // compared case sensitively?
- #[inline]
- #[must_use]
- pub fn get(&self, key: VarName<'_>) -> Option<&Value> {
- self.variables.get(key.as_str())
- }
-}
-
-impl Context for SimpleContext {
- fn visit<V: Visitor>(&self, visitor: V) -> V::Result {
- use crate::template::context::{AssocVisitor, ListVisitor};
-
- let name = visitor.var_name().as_str();
- match self.variables.get(name) {
- None | Some(Value::Undefined) => visitor.visit_undefined(),
- Some(Value::String(s)) => visitor.visit_string(s),
- Some(Value::List(list)) => {
- let mut visitor = visitor.visit_list();
- if let ControlFlow::Break(res) =
- list.iter().try_for_each(|item| visitor.visit_item(item))
- {
- return res;
- }
- visitor.finish()
- }
- Some(Value::Assoc(list)) => {
- let mut visitor = visitor.visit_assoc();
- if let ControlFlow::Break(res) =
- list.iter().try_for_each(|(k, v)| visitor.visit_entry(k, v))
- {
- return res;
- }
- visitor.finish()
- }
- }
- }
-}
diff --git a/vendor/iri-string/src/template/string.rs b/vendor/iri-string/src/template/string.rs
deleted file mode 100644
index 9ba53a75..00000000
--- a/vendor/iri-string/src/template/string.rs
+++ /dev/null
@@ -1,647 +0,0 @@
-//! Template string types.
-
-use core::fmt;
-
-#[cfg(feature = "alloc")]
-use alloc::borrow::Cow;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::boxed::Box;
-#[cfg(feature = "alloc")]
-use alloc::rc::Rc;
-#[cfg(feature = "alloc")]
-use alloc::string::String;
-#[cfg(feature = "alloc")]
-use alloc::sync::Arc;
-
-use crate::spec::Spec;
-use crate::template::components::{VarListIter, VarName};
-use crate::template::context::{Context, DynamicContext};
-use crate::template::error::{Error, ErrorKind};
-use crate::template::expand::{expand_whole_dynamic, Chunk, Chunks, Expanded};
-use crate::template::parser::validate_template_str;
-
-#[cfg(feature = "alloc")]
-pub use self::owned::UriTemplateString;
-
-/// Implements `PartialEq` and `PartialOrd`.
-macro_rules! impl_cmp {
- ($ty_common:ty, $ty_lhs:ty, $ty_rhs:ty) => {
- impl PartialEq<$ty_rhs> for $ty_lhs {
- #[inline]
- fn eq(&self, o: &$ty_rhs) -> bool {
- <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
- }
- }
- impl PartialEq<$ty_lhs> for $ty_rhs {
- #[inline]
- fn eq(&self, o: &$ty_lhs) -> bool {
- <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
- }
- }
- impl PartialOrd<$ty_rhs> for $ty_lhs {
- #[inline]
- fn partial_cmp(&self, o: &$ty_rhs) -> Option<core::cmp::Ordering> {
- <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
- }
- }
- impl PartialOrd<$ty_lhs> for $ty_rhs {
- #[inline]
- fn partial_cmp(&self, o: &$ty_lhs) -> Option<core::cmp::Ordering> {
- <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
- }
- }
- };
-}
-
-#[cfg(feature = "alloc")]
-mod owned;
-
-/// A borrowed slice of a URI template.
-///
-/// URI Template is defined by [RFC 6570].
-///
-/// Note that "URI Template" can also be used for IRI.
-///
-/// [RFC 6570]: https://www.rfc-editor.org/rfc/rfc6570.html
-///
-/// # Valid values
-///
-/// This type can have a URI template string.
-///
-/// # Applied errata
-///
-/// [Errata ID 6937](https://www.rfc-editor.org/errata/eid6937) is applied, so
-/// single quotes are allowed to appear in an URI template.
-///
-/// ```
-/// # use iri_string::template::Error;
-/// use iri_string::template::UriTemplateStr;
-///
-/// let template = UriTemplateStr::new("'quoted'")?;
-/// # Ok::<_, Error>(())
-/// ```
-#[cfg_attr(feature = "serde", derive(serde::Serialize))]
-#[cfg_attr(feature = "serde", serde(transparent))]
-#[repr(transparent)]
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct UriTemplateStr {
- /// The raw string.
- inner: str,
-}
-
-impl UriTemplateStr {
- /// Creates a new string.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// use iri_string::template::UriTemplateStr;
- ///
- /// let template = UriTemplateStr::new("/users/{username}")?;
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn new(s: &str) -> Result<&Self, Error> {
- TryFrom::try_from(s)
- }
-
- /// Creates a new string without validation.
- ///
- /// This does not validate the given string, so it is caller's
- /// responsibility to ensure the given string is valid.
- ///
- /// # Safety
- ///
- /// The given string must be syntactically valid as `Self` type.
- /// If not, any use of the returned value or the call of this
- /// function itself may result in undefined behavior.
- #[inline]
- #[must_use]
- pub unsafe fn new_unchecked(s: &str) -> &Self {
- // SAFETY: `new_always_unchecked` requires the same precondition
- // as `new_always_unchecked`.
- unsafe { Self::new_always_unchecked(s) }
- }
-
- /// Creates a new string without any validation.
- ///
- /// This does not validate the given string at any time.
- ///
- /// Intended for internal use.
- ///
- /// # Safety
- ///
- /// The given string must be valid.
- #[inline]
- #[must_use]
- unsafe fn new_always_unchecked(s: &str) -> &Self {
- // SAFETY: the cast is safe since `Self` type has `repr(transparent)`
- // attribute and the content is guaranteed as valid by the
- // precondition of the function.
- unsafe { &*(s as *const str as *const Self) }
- }
-
- /// Returns the template as a plain `&str`.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// use iri_string::template::UriTemplateStr;
- ///
- /// let template = UriTemplateStr::new("/users/{username}")?;
- /// assert_eq!(template.as_str(), "/users/{username}");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn as_str(&self) -> &str {
- self.as_ref()
- }
-
- /// Returns the template string length.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// use iri_string::template::UriTemplateStr;
- ///
- /// let template = UriTemplateStr::new("/users/{username}")?;
- /// assert_eq!(template.len(), "/users/{username}".len());
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn len(&self) -> usize {
- self.as_str().len()
- }
-
- /// Returns whether the string is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// use iri_string::template::UriTemplateStr;
- ///
- /// let template = UriTemplateStr::new("/users/{username}")?;
- /// assert!(!template.is_empty());
- ///
- /// let empty = UriTemplateStr::new("")?;
- /// assert!(empty.is_empty());
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn is_empty(&self) -> bool {
- self.as_str().is_empty()
- }
-}
-
-impl UriTemplateStr {
- /// Expands the template with the given context.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::spec::UriSpec;
- /// use iri_string::template::UriTemplateStr;
- /// use iri_string::template::simple_context::SimpleContext;
- ///
- /// let mut context = SimpleContext::new();
- /// context.insert("username", "foo");
- ///
- /// let template = UriTemplateStr::new("/users/{username}")?;
- /// let expanded = template.expand::<UriSpec, _>(&context)?;
- ///
- /// assert_eq!(
- /// expanded.to_string(),
- /// "/users/foo"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// You can control allowed characters in the output by changing spec type.
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::spec::{IriSpec, UriSpec};
- /// use iri_string::template::UriTemplateStr;
- /// use iri_string::template::simple_context::SimpleContext;
- ///
- /// let mut context = SimpleContext::new();
- /// context.insert("alpha", "\u{03B1}");
- ///
- /// let template = UriTemplateStr::new("{?alpha}")?;
- ///
- /// assert_eq!(
- /// template.expand::<UriSpec, _>(&context)?.to_string(),
- /// "?alpha=%CE%B1",
- /// "a URI cannot contain Unicode alpha (U+03B1), so it should be escaped"
- /// );
- /// assert_eq!(
- /// template.expand::<IriSpec, _>(&context)?.to_string(),
- /// "?alpha=\u{03B1}",
- /// "an IRI can contain Unicode alpha (U+03B1), so it written as is"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn expand<'a, S: Spec, C: Context>(
- &'a self,
- context: &'a C,
- ) -> Result<Expanded<'a, S, C>, Error> {
- Expanded::new(self, context)
- }
-
- /// Expands the template with the given dynamic context.
- ///
- #[cfg_attr(
- feature = "alloc",
- doc = concat!(
- "If you need the allocated [`String`], use",
- "[`expand_dynamic_to_string`][`Self::expand_dynamic_to_string`]."
- )
- )]
- ///
- /// See the documentation for [`DynamicContext`] for usage.
- pub fn expand_dynamic<S: Spec, W: fmt::Write, C: DynamicContext>(
- &self,
- writer: &mut W,
- context: &mut C,
- ) -> Result<(), Error> {
- expand_whole_dynamic::<S, _, _>(self, writer, context)
- }
-
- /// Expands the template into a string, with the given dynamic context.
- ///
- /// This is basically [`expand_dynamic`][`Self::expand_dynamic`] method
- /// that returns an owned string instead of writing to the given writer.
- ///
- /// See the documentation for [`DynamicContext`] for usage.
- ///
- /// # Examples
- ///
- /// ```
- /// # #[cfg(feature = "alloc")]
- /// # extern crate alloc;
- /// # use iri_string::template::Error;
- /// # #[cfg(feature = "alloc")] {
- /// # use alloc::string::String;
- /// use iri_string::template::UriTemplateStr;
- /// # use iri_string::template::context::{DynamicContext, Visitor, VisitPurpose};
- /// use iri_string::spec::UriSpec;
- ///
- /// struct MyContext<'a> {
- /// // See the documentation for `DynamicContext`.
- /// # /// Target path.
- /// # target: &'a str,
- /// # /// Username.
- /// # username: Option<&'a str>,
- /// # /// A flag to remember whether the URI template
- /// # /// attempted to use `username` variable.
- /// # username_visited: bool,
- /// }
- /// #
- /// # impl DynamicContext for MyContext<'_> {
- /// # fn on_expansion_start(&mut self) {
- /// # // Reset the state.
- /// # self.username_visited = false;
- /// # }
- /// # fn visit_dynamic<V: Visitor>(&mut self, visitor: V) -> V::Result {
- /// # match visitor.var_name().as_str() {
- /// # "target" => visitor.visit_string(self.target),
- /// # "username" => {
- /// # if visitor.purpose() == VisitPurpose::Expand {
- /// # // The variable `username` is being used
- /// # // on the template expansion.
- /// # // Don't care whether `username` is defined or not.
- /// # self.username_visited = true;
- /// # }
- /// # if let Some(username) = &self.username {
- /// # visitor.visit_string(username)
- /// # } else {
- /// # visitor.visit_undefined()
- /// # }
- /// # }
- /// # _ => visitor.visit_undefined(),
- /// # }
- /// # }
- /// # }
- ///
- /// let mut context = MyContext {
- /// target: "/posts/1",
- /// username: Some("the_admin"),
- /// username_visited: false,
- /// };
- ///
- /// // No access to the variable `username`.
- /// let template = UriTemplateStr::new("{+target}{?username}")?;
- /// let s = template.expand_dynamic_to_string::<UriSpec, _>(&mut context)?;
- /// assert_eq!(s, "/posts/1?username=the_admin");
- /// assert!(context.username_visited);
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[cfg(feature = "alloc")]
- pub fn expand_dynamic_to_string<S: Spec, C: DynamicContext>(
- &self,
- context: &mut C,
- ) -> Result<String, Error> {
- let mut buf = String::new();
- expand_whole_dynamic::<S, _, _>(self, &mut buf, context)?;
- Ok(buf)
- }
-
- /// Returns an iterator of variables in the template.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::template::Error;
- /// use iri_string::template::UriTemplateStr;
- ///
- /// let template = UriTemplateStr::new("foo{/bar*,baz:4}{?qux}{&bar*}")?;
- /// let mut vars = template.variables();
- /// assert_eq!(vars.next().map(|var| var.as_str()), Some("bar"));
- /// assert_eq!(vars.next().map(|var| var.as_str()), Some("baz"));
- /// assert_eq!(vars.next().map(|var| var.as_str()), Some("qux"));
- /// assert_eq!(vars.next().map(|var| var.as_str()), Some("bar"));
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn variables(&self) -> UriTemplateVariables<'_> {
- UriTemplateVariables::new(self)
- }
-}
-
-impl fmt::Debug for UriTemplateStr {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("UriTemplateStr").field(&&self.inner).finish()
- }
-}
-
-impl AsRef<str> for UriTemplateStr {
- #[inline]
- fn as_ref(&self) -> &str {
- &self.inner
- }
-}
-
-impl AsRef<UriTemplateStr> for UriTemplateStr {
- #[inline]
- fn as_ref(&self) -> &UriTemplateStr {
- self
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<'a> From<&'a UriTemplateStr> for Cow<'a, UriTemplateStr> {
- #[inline]
- fn from(s: &'a UriTemplateStr) -> Self {
- Cow::Borrowed(s)
- }
-}
-
-#[cfg(feature = "alloc")]
-impl From<&UriTemplateStr> for Arc<UriTemplateStr> {
- fn from(s: &UriTemplateStr) -> Self {
- let inner: &str = s.as_str();
- let buf = Arc::<str>::from(inner);
- // SAFETY: `UriTemplateStr` has `repr(transparent)` attribute, so
- // the memory layouts of `Arc<str>` and `Arc<UriTemplateStr>` are
- // compatible.
- unsafe {
- let raw: *const str = Arc::into_raw(buf);
- Self::from_raw(raw as *const UriTemplateStr)
- }
- }
-}
-
-#[cfg(feature = "alloc")]
-impl From<&UriTemplateStr> for Box<UriTemplateStr> {
- fn from(s: &UriTemplateStr) -> Self {
- let inner: &str = s.as_str();
- let buf = Box::<str>::from(inner);
- // SAFETY: `UriTemplateStr` has `repr(transparent)` attribute, so
- // the memory layouts of `Box<str>` and `Box<UriTemplateStr>` are
- // compatible.
- unsafe {
- let raw: *mut str = Box::into_raw(buf);
- Self::from_raw(raw as *mut UriTemplateStr)
- }
- }
-}
-
-#[cfg(feature = "alloc")]
-impl From<&UriTemplateStr> for Rc<UriTemplateStr> {
- fn from(s: &UriTemplateStr) -> Self {
- let inner: &str = s.as_str();
- let buf = Rc::<str>::from(inner);
- // SAFETY: `UriTemplateStr` has `repr(transparent)` attribute, so
- // the memory layouts of `Rc<str>` and `Rc<UriTemplateStr>` are
- // compatible.
- unsafe {
- let raw: *const str = Rc::into_raw(buf);
- Self::from_raw(raw as *const UriTemplateStr)
- }
- }
-}
-
-impl<'a> From<&'a UriTemplateStr> for &'a str {
- #[inline]
- fn from(s: &'a UriTemplateStr) -> &'a str {
- s.as_ref()
- }
-}
-
-impl<'a> TryFrom<&'a str> for &'a UriTemplateStr {
- type Error = Error;
-
- #[inline]
- fn try_from(s: &'a str) -> Result<Self, Self::Error> {
- match validate_template_str(s) {
- // SAFETY: just checked the string is valid.
- Ok(()) => Ok(unsafe { UriTemplateStr::new_always_unchecked(s) }),
- Err(e) => Err(e),
- }
- }
-}
-
-impl<'a> TryFrom<&'a [u8]> for &'a UriTemplateStr {
- type Error = Error;
-
- #[inline]
- fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
- let s = core::str::from_utf8(bytes)
- .map_err(|e| Error::new(ErrorKind::InvalidUtf8, e.valid_up_to()))?;
- match validate_template_str(s) {
- // SAFETY: just checked the string is valid.
- Ok(()) => Ok(unsafe { UriTemplateStr::new_always_unchecked(s) }),
- Err(e) => Err(e),
- }
- }
-}
-
-impl_cmp!(str, str, UriTemplateStr);
-impl_cmp!(str, &str, UriTemplateStr);
-impl_cmp!(str, str, &UriTemplateStr);
-
-impl fmt::Display for UriTemplateStr {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str(self.as_str())
- }
-}
-
-/// Serde deserializer implementation.
-#[cfg(feature = "serde")]
-mod __serde_slice {
- use super::UriTemplateStr;
-
- use core::fmt;
-
- use serde::{
- de::{self, Visitor},
- Deserialize, Deserializer,
- };
-
- /// Custom borrowed string visitor.
- #[derive(Debug, Clone, Copy)]
- struct CustomStrVisitor;
-
- impl<'de> Visitor<'de> for CustomStrVisitor {
- type Value = &'de UriTemplateStr;
-
- #[inline]
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("URI template string")
- }
-
- #[inline]
- fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- <&'de UriTemplateStr as TryFrom<&'de str>>::try_from(v).map_err(E::custom)
- }
- }
-
- // About `'de` and `'a`, see
- // <https://serde.rs/lifetimes.html#the-deserializede-lifetime>.
- impl<'a, 'de: 'a> Deserialize<'de> for &'a UriTemplateStr {
- #[inline]
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- deserializer.deserialize_string(CustomStrVisitor)
- }
- }
-}
-
-/// An iterator of variables in a URI template.
-#[derive(Debug, Clone)]
-pub struct UriTemplateVariables<'a> {
- /// Chunks iterator.
- chunks: Chunks<'a>,
- /// Variables in the last chunk.
- vars_in_chunk: Option<VarListIter<'a>>,
-}
-
-impl<'a> UriTemplateVariables<'a> {
- /// Creates a variables iterator from the URI template.
- #[inline]
- #[must_use]
- fn new(template: &'a UriTemplateStr) -> Self {
- Self {
- chunks: Chunks::new(template),
- vars_in_chunk: None,
- }
- }
-}
-
-impl<'a> Iterator for UriTemplateVariables<'a> {
- type Item = VarName<'a>;
-
- fn next(&mut self) -> Option<Self::Item> {
- loop {
- if let Some(vars) = &mut self.vars_in_chunk {
- match vars.next() {
- Some((_len, spec)) => return Some(spec.name()),
- None => self.vars_in_chunk = None,
- }
- }
- let expr = self.chunks.find_map(|chunk| match chunk {
- Chunk::Literal(_) => None,
- Chunk::Expr(v) => Some(v),
- });
- self.vars_in_chunk = match expr {
- Some(expr) => Some(expr.decompose().1.into_iter()),
- None => return None,
- }
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use crate::spec::IriSpec;
- use crate::template::context::{AssocVisitor, ListVisitor, Visitor};
-
- struct TestContext;
- impl Context for TestContext {
- fn visit<V: Visitor>(&self, visitor: V) -> V::Result {
- match visitor.var_name().as_str() {
- "str" => visitor.visit_string("string"),
- "list" => visitor
- .visit_list()
- .visit_items_and_finish(["item0", "item1", "item2"]),
- "assoc" => visitor
- .visit_assoc()
- .visit_entries_and_finish([("key0", "value0"), ("key1", "value1")]),
- _ => visitor.visit_undefined(),
- }
- }
- }
-
- #[test]
- fn expand_error_pos() {
- {
- let e = UriTemplateStr::new("foo{list:4}")
- .unwrap()
- .expand::<IriSpec, _>(&TestContext)
- .err()
- .map(|e| e.location());
- assert_eq!(e, Some("foo{".len()));
- }
-
- {
- let e = UriTemplateStr::new("foo{/list*,list:4}")
- .unwrap()
- .expand::<IriSpec, _>(&TestContext)
- .err()
- .map(|e| e.location());
- assert_eq!(e, Some("foo{/list*,".len()));
- }
-
- {
- let e = UriTemplateStr::new("foo{/str:3,list*,assoc:4}")
- .unwrap()
- .expand::<IriSpec, _>(&TestContext)
- .err()
- .map(|e| e.location());
- assert_eq!(e, Some("foo{/str:3,list*,".len()));
- }
- }
-}
diff --git a/vendor/iri-string/src/template/string/owned.rs b/vendor/iri-string/src/template/string/owned.rs
deleted file mode 100644
index afd201b3..00000000
--- a/vendor/iri-string/src/template/string/owned.rs
+++ /dev/null
@@ -1,296 +0,0 @@
-//! Owned `UriTemplateString`.
-
-use core::fmt;
-
-use alloc::borrow::Cow;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::borrow::ToOwned;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::boxed::Box;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-
-use crate::template::error::{CreationError, Error, ErrorKind};
-use crate::template::parser::validate_template_str;
-use crate::template::string::UriTemplateStr;
-
-/// An owned slice of a URI template.
-///
-/// URI Template is defined by [RFC 6570].
-///
-/// Note that "URI Template" can also be used for IRI.
-///
-/// [RFC 6570]: https://www.rfc-editor.org/rfc/rfc6570.html
-///
-/// # Valid values
-///
-/// This type can have a URI template string.
-// Note that `From<$ty> for {Arc,Rc}<$slice>` is currently not implemented since
-// this won't reuse allocated memory and hides internal memory reallocation. See
-// <https://github.com/lo48576/iri-string/issues/20#issuecomment-1105207849>.
-// However, this is not decided with firm belief or opinion, so there would be
-// a chance that they are implemented in future.
-#[cfg_attr(feature = "serde", derive(serde::Serialize))]
-#[cfg_attr(feature = "serde", serde(transparent))]
-#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct UriTemplateString {
- /// Inner data.
- inner: String,
-}
-
-impl UriTemplateString {
- /// Creates a new string without validation.
- ///
- /// This does not validate the given string, so it is caller's
- /// responsibility to ensure the given string is valid.
- ///
- /// # Safety
- ///
- /// The given string must be syntactically valid as `Self` type.
- /// If not, any use of the returned value or the call of this
- /// function itself may result in undefined behavior.
- #[inline]
- #[must_use]
- pub unsafe fn new_unchecked(s: alloc::string::String) -> Self {
- // The construction itself can be written in safe Rust, but
- // every other place including unsafe functions expects
- // `self.inner` to be syntactically valid as `Self`. In order to
- // make them safe, the construction should validate the value
- // or at least should require users to validate the value by
- // making the function `unsafe`.
- Self { inner: s }
- }
-
- /// Shrinks the capacity of the inner buffer to match its length.
- #[inline]
- pub fn shrink_to_fit(&mut self) {
- self.inner.shrink_to_fit()
- }
-
- /// Returns the internal buffer capacity in bytes.
- #[inline]
- #[must_use]
- pub fn capacity(&self) -> usize {
- self.inner.capacity()
- }
-
- /// Returns the borrowed IRI string slice.
- ///
- /// This is equivalent to `&*self`.
- #[inline]
- #[must_use]
- pub fn as_slice(&self) -> &UriTemplateStr {
- self.as_ref()
- }
-
- /// Appends the template string.
- #[inline]
- pub fn append(&mut self, other: &UriTemplateStr) {
- self.inner.push_str(other.as_str());
- debug_assert!(validate_template_str(self.as_str()).is_ok());
- }
-}
-
-impl AsRef<str> for UriTemplateString {
- #[inline]
- fn as_ref(&self) -> &str {
- &self.inner
- }
-}
-
-impl AsRef<UriTemplateStr> for UriTemplateString {
- #[inline]
- fn as_ref(&self) -> &UriTemplateStr {
- // SAFETY: `UriTemplateString and `UriTemplateStr` requires same validation,
- // so the content of `self: &UriTemplateString` must be valid as `UriTemplateStr`.
- unsafe { UriTemplateStr::new_always_unchecked(AsRef::<str>::as_ref(self)) }
- }
-}
-
-impl core::borrow::Borrow<str> for UriTemplateString {
- #[inline]
- fn borrow(&self) -> &str {
- self.as_ref()
- }
-}
-
-impl core::borrow::Borrow<UriTemplateStr> for UriTemplateString {
- #[inline]
- fn borrow(&self) -> &UriTemplateStr {
- self.as_ref()
- }
-}
-
-impl ToOwned for UriTemplateStr {
- type Owned = UriTemplateString;
-
- #[inline]
- fn to_owned(&self) -> Self::Owned {
- self.into()
- }
-}
-
-impl From<&'_ UriTemplateStr> for UriTemplateString {
- #[inline]
- fn from(s: &UriTemplateStr) -> Self {
- // This is safe because `s` must be valid.
- Self {
- inner: alloc::string::String::from(s.as_str()),
- }
- }
-}
-
-impl From<UriTemplateString> for alloc::string::String {
- #[inline]
- fn from(s: UriTemplateString) -> Self {
- s.inner
- }
-}
-
-impl<'a> From<UriTemplateString> for Cow<'a, UriTemplateStr> {
- #[inline]
- fn from(s: UriTemplateString) -> Cow<'a, UriTemplateStr> {
- Cow::Owned(s)
- }
-}
-
-impl From<UriTemplateString> for Box<UriTemplateStr> {
- #[inline]
- fn from(s: UriTemplateString) -> Box<UriTemplateStr> {
- let inner: String = s.into();
- let buf = Box::<str>::from(inner);
- // SAFETY: `UriTemplateStr` has `repr(transparent)` attribute, so
- // the memory layouts of `Box<str>` and `Box<UriTemplateStr>` are
- // compatible. Additionally, `UriTemplateString` and `UriTemplateStr`
- // require the same syntax.
- unsafe {
- let raw: *mut str = Box::into_raw(buf);
- Box::<UriTemplateStr>::from_raw(raw as *mut UriTemplateStr)
- }
- }
-}
-
-impl TryFrom<&'_ str> for UriTemplateString {
- type Error = Error;
-
- #[inline]
- fn try_from(s: &str) -> Result<Self, Self::Error> {
- <&UriTemplateStr>::try_from(s).map(Into::into)
- }
-}
-
-impl TryFrom<&'_ [u8]> for UriTemplateString {
- type Error = Error;
-
- #[inline]
- fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
- let s = core::str::from_utf8(bytes)
- .map_err(|e| Error::new(ErrorKind::InvalidUtf8, e.valid_up_to()))?;
- <&UriTemplateStr>::try_from(s).map(Into::into)
- }
-}
-
-impl core::convert::TryFrom<alloc::string::String> for UriTemplateString {
- type Error = CreationError<String>;
-
- #[inline]
- fn try_from(s: alloc::string::String) -> Result<Self, Self::Error> {
- match <&UriTemplateStr>::try_from(s.as_str()) {
- Ok(_) => {
- // This is safe because `<&UriTemplateStr>::try_from(s)?` ensures
- // that the string `s` is valid.
- Ok(Self { inner: s })
- }
- Err(e) => Err(CreationError::new(e, s)),
- }
- }
-}
-
-impl alloc::str::FromStr for UriTemplateString {
- type Err = Error;
-
- #[inline]
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- TryFrom::try_from(s)
- }
-}
-
-impl core::ops::Deref for UriTemplateString {
- type Target = UriTemplateStr;
-
- #[inline]
- fn deref(&self) -> &UriTemplateStr {
- self.as_ref()
- }
-}
-
-impl_cmp!(str, UriTemplateStr, Cow<'_, str>);
-impl_cmp!(str, &UriTemplateStr, Cow<'_, str>);
-
-impl_cmp!(str, str, UriTemplateString);
-impl_cmp!(str, &str, UriTemplateString);
-impl_cmp!(str, Cow<'_, str>, UriTemplateString);
-impl_cmp!(str, String, UriTemplateString);
-
-impl fmt::Display for UriTemplateString {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str(self.as_str())
- }
-}
-
-/// Serde deserializer implementation.
-#[cfg(feature = "serde")]
-mod __serde_owned {
- use super::UriTemplateString;
-
- use core::fmt;
-
- #[cfg(all(feature = "alloc", feature = "serde", not(feature = "std")))]
- use alloc::string::String;
-
- use serde::{
- de::{self, Visitor},
- Deserialize, Deserializer,
- };
-
- /// Custom owned string visitor.
- #[derive(Debug, Clone, Copy)]
- struct CustomStringVisitor;
-
- impl Visitor<'_> for CustomStringVisitor {
- type Value = UriTemplateString;
-
- #[inline]
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("URI template string")
- }
-
- #[inline]
- fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- <UriTemplateString as TryFrom<&str>>::try_from(v).map_err(E::custom)
- }
-
- #[cfg(feature = "serde")]
- #[inline]
- fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- <UriTemplateString as TryFrom<String>>::try_from(v).map_err(E::custom)
- }
- }
-
- impl<'de> Deserialize<'de> for UriTemplateString {
- #[inline]
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- deserializer.deserialize_str(CustomStringVisitor)
- }
- }
-}
diff --git a/vendor/iri-string/src/types.rs b/vendor/iri-string/src/types.rs
deleted file mode 100644
index 38e734c9..00000000
--- a/vendor/iri-string/src/types.rs
+++ /dev/null
@@ -1,224 +0,0 @@
-//! URI and IRI types.
-//!
-//! # URI and IRI
-//!
-//! IRIs (Internationalized Resource Identifiers) are defined in [RFC 3987],
-//! and URIs (Uniform Resource Identifiers) are defined in [RFC 3986].
-//!
-//! URI consists of only ASCII characters, and is a subset of IRI.
-//!
-//! IRIs are defined as below:
-//!
-//! ```text
-//! IRI = scheme ":" ihier-part [ "?" iquery ] [ "#" ifragment ]
-//! IRI-reference = IRI / irelative-ref
-//! absolute-IRI = scheme ":" ihier-part [ "?" iquery ]
-//! irelative-ref = irelative-part [ "?" iquery ] [ "#" ifragment ]
-//! (`irelative-part` is roughly same as `ihier-part`.)
-//! ```
-//!
-//! Definitions for URIs are almost same, but they cannot have non-ASCII characters.
-//!
-//! # Types
-//!
-//! Types can be categorized by:
-//!
-//! * syntax,
-//! * spec, and
-//! * ownership.
-//!
-//! ## Syntax
-//!
-//! Since URIs and IRIs have almost same syntax and share algorithms, they are implemented by
-//! generic types.
-//!
-//! * [`RiStr`] and [`RiString`]
-//! + String types for `IRI` and `URI` rules.
-//! * [`RiAbsoluteStr`] and [`RiAbsoluteString`]
-//! + String types for `absolute-IRI` and `absolute-URI` rules.
-//! * [`RiReferenceStr`] and [`RiReferenceString`]
-//! + String types for `IRI-reference` and `URI-reference` rules.
-//! * [`RiRelativeStr`] and [`RiRelativeString`]
-//! + String types for `irelative-ref` and `relative-ref` rules.
-//! * [`RiFragmentStr`] and [`RiFragmentString`]
-//! + String types for `ifragment` and `fragment` rules.
-//! + Note that these types represents a substring of an IRI / URI references.
-//! They are not intended to used directly as an IRI / URI references.
-//!
-//! "Ri" stands for "Resource Identifier".
-//!
-//! ## Spec
-//!
-//! These types have a type parameter, which represents RFC specification.
-//! [`IriSpec`] represents [RFC 3987] spec, and [`UriSpec`] represents [RFC 3986] spec.
-//! For example, `RiAbsoluteStr<IriSpec>` can have `absolute-IRI` string value,
-//! and `RiReferenceStr<UriSpec>` can have `URI-reference` string value.
-//!
-//! ## Ownership
-//!
-//! String-like types have usually two variations, borrowed and owned.
-//!
-//! Borrowed types (such as `str`, `Path`, `OsStr`) are unsized, and used by reference style.
-//! Owned types (such as `String`, `PathBuf`, `OsString`) are sized, and requires heap allocation.
-//! Owned types can be coerced to a borrowed type (for example, `&String` is automatically coerced
-//! to `&str` in many context).
-//!
-//! IRI / URI types have same variations, `RiFooStr` and `RiFooString`
-//! (`Foo` part represents syntax).
-//! They are very similar to `&str` and `String`.
-//! `Deref` is implemented, `RiFooStr::len()` is available, `&RiFooString` can be coerced to
-//! `&RiFooStr`, `Cow<'_, RiFooStr>` and `Box<RiFooStr>` is available, and so on.
-//!
-//! # Hierarchy and safe conversion
-//!
-//! IRI syntaxes have the hierarchy below.
-//!
-//! ```text
-//! RiReferenceStr
-//! |-- RiStr
-//! | `-- RiAbsoluteStr
-//! `-- RiRelativeStr
-//! ```
-//!
-//! Therefore, the conversions below are safe and cheap:
-//!
-//! * `RiStr -> RiReferenceStr`
-//! * `RiAbsoluteStr -> RiStr`
-//! * `RiAbsoluteStr -> RiReferenceStr`
-//! * `RiRelativeStr -> RiReferenceStr`
-//!
-//! For safely convertible types (consider `FooStr -> BarStr` is safe), traits
-//! below are implemented:
-//!
-//! * `AsRef<BarStr> for FooStr`
-//! * `AsRef<BarStr> for FooString`
-//! * `From<FooString> for BarString`
-//! * `PartialEq<FooStr> for BarStr`, and lots of impls like that
-//! + `PartialEq` and `ParitalOrd`.
-//! + Slice, owned, `Cow`, reference, etc...
-//!
-//! ## Fallible conversions
-//!
-//! Fallible conversions are implemented from plain string into IRI strings.
-//!
-//! * `TryFrom<&str> for &FooStr`
-//! * `TryFrom<&str> for FooString`
-//! * `TryFrom<String> for FooString`
-//! * `FromStr for FooString`
-//!
-//! Some IRI string types provide more convenient methods to convert between IRI types.
-//! For example, [`RiReferenceString::into_iri()`] tries to convert an IRI reference into an IRI,
-//! and returns `Result<IriString, IriRelativeString>`.
-//! This is because an IRI reference is valid as an IRI or a relative IRI reference.
-//! Such methods are usually more efficient than using `TryFrom` for plain strings, because they
-//! prevents you from losing ownership of a string, and does a conversion without extra memory
-//! allocation.
-//!
-//! # Aliases
-//!
-//! This module contains type aliases for RFC 3986 URI types and RFC 3987 IRI types.
-//!
-//! `IriFooStr{,ing}` are aliases of `RiFooStr{,ing}<IriSpec>`, and `UriFooStr{,ing}` are aliases
-//! of `RiFooStr{,ing}<UriSpec>`.
-//!
-//! # Wrapped string types
-//!
-//! Similar to string types in std (such as `str`, `std::path::Path`, and `std::ffi::OsStr`),
-//! IRI string types in this crate provides convenient conversions to:
-//!
-//! * `std::box::Box`,
-//! * `std::borrow::Cow`,
-//! * `std::rc::Rc`, and
-//! * `std::sync::Arc`.
-//!
-//! ```
-//! # use iri_string::validate::Error;
-//! # #[cfg(feature = "std")] {
-//! use std::borrow::Cow;
-//! use std::rc::Rc;
-//! use std::sync::Arc;
-//!
-//! use iri_string::types::IriStr;
-//!
-//! let iri = IriStr::new("http://example.com/")?;
-//! let iri_owned = iri.to_owned();
-//!
-//! // From slice.
-//! let cow_1_1: Cow<'_, IriStr> = iri.into();
-//! let cow_1_2 = Cow::<'_, IriStr>::from(iri);
-//! assert!(matches!(cow_1_1, Cow::Borrowed(_)));
-//! assert!(matches!(cow_1_2, Cow::Borrowed(_)));
-//! // From owned.
-//! let cow_2_1: Cow<'_, IriStr> = iri_owned.clone().into();
-//! let cow_2_2 = Cow::<'_, IriStr>::from(iri_owned.clone());
-//! assert!(matches!(cow_2_1, Cow::Owned(_)));
-//! assert!(matches!(cow_2_2, Cow::Owned(_)));
-//!
-//! // From slice.
-//! let box_1_1: Box<IriStr> = iri.into();
-//! let box_1_2 = Box::<IriStr>::from(iri);
-//! // From owned.
-//! let box_2_1: Box<IriStr> = iri_owned.clone().into();
-//! let box_2_2 = Box::<IriStr>::from(iri_owned.clone());
-//!
-//! // From slice.
-//! let rc_1_1: Rc<IriStr> = iri.into();
-//! let rc_1_2 = Rc::<IriStr>::from(iri);
-//! // From owned.
-//! // Note that `From<owned> for Rc<borrowed>` is not implemented for now.
-//! // Get borrowed string by `.as_slice()` and convert it.
-//! let rc_2_1: Rc<IriStr> = iri_owned.clone().as_slice().into();
-//! let rc_2_2 = Rc::<IriStr>::from(iri_owned.clone().as_slice());
-//!
-//! // From slice.
-//! let arc_1_1: Arc<IriStr> = iri.into();
-//! let arc_1_2 = Arc::<IriStr>::from(iri);
-//! // From owned.
-//! // Note that `From<owned> for Arc<borrowed>` is not implemented for now.
-//! // Get borrowed string by `.as_slice()` and convert it.
-//! let arc_2_1: Arc<IriStr> = iri_owned.clone().as_slice().into();
-//! let arc_2_2 = Arc::<IriStr>::from(iri_owned.clone().as_slice());
-//! # }
-//! # Ok::<_, Error>(())
-//! ```
-//!
-//! [RFC 3986]: https://tools.ietf.org/html/rfc3986
-//! [RFC 3987]: https://tools.ietf.org/html/rfc3987
-//! [`RiStr`]: struct.RiStr.html
-//! [`RiString`]: struct.RiString.html
-//! [`RiAbsoluteStr`]: struct.RiAbsoluteStr.html
-//! [`RiAbsoluteString`]: struct.RiAbsoluteString.html
-//! [`RiFragmentStr`]: struct.RiFragmentStr.html
-//! [`RiFragmentString`]: struct.RiFragmentString.html
-//! [`RiReferenceStr`]: struct.RiReferenceStr.html
-//! [`RiReferenceString`]: struct.RiReferenceString.html
-//! [`RiReferenceString::into_iri()`]: struct.RiReferenceString.html#method.into_iri
-//! [`RiRelativeStr`]: struct.RiRelativeStr.html
-//! [`RiRelativeString`]: struct.RiRelativeString.html
-//! [`IriSpec`]: ../spec/enum.IriSpec.html
-//! [`UriSpec`]: ../spec/enum.UriSpec.html
-
-#[cfg(feature = "alloc")]
-pub use self::{
- generic::{
- CreationError, RiAbsoluteString, RiFragmentString, RiQueryString, RiReferenceString,
- RiRelativeString, RiString,
- },
- iri::{
- IriAbsoluteString, IriFragmentString, IriQueryString, IriReferenceString,
- IriRelativeString, IriString,
- },
- uri::{
- UriAbsoluteString, UriFragmentString, UriQueryString, UriReferenceString,
- UriRelativeString, UriString,
- },
-};
-pub use self::{
- generic::{RiAbsoluteStr, RiFragmentStr, RiQueryStr, RiReferenceStr, RiRelativeStr, RiStr},
- iri::{IriAbsoluteStr, IriFragmentStr, IriQueryStr, IriReferenceStr, IriRelativeStr, IriStr},
- uri::{UriAbsoluteStr, UriFragmentStr, UriQueryStr, UriReferenceStr, UriRelativeStr, UriStr},
-};
-
-pub(crate) mod generic;
-mod iri;
-mod uri;
diff --git a/vendor/iri-string/src/types/generic.rs b/vendor/iri-string/src/types/generic.rs
deleted file mode 100644
index 9e631069..00000000
--- a/vendor/iri-string/src/types/generic.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-//! Generic resource identifier types.
-//!
-//! ```text
-//! IRI = scheme ":" ihier-part [ "?" iquery ] [ "#" ifragment ]
-//! IRI-reference = IRI / irelative-ref
-//! absolute-IRI = scheme ":" ihier-part [ "?" iquery ]
-//! irelative-ref = irelative-part [ "?" iquery ] [ "#" ifragment ]
-//! (`irelative-part` is roughly same as `ihier-part`.)
-//! ```
-//!
-//! Hierarchy:
-//!
-//! ```text
-//! RiReferenceStr
-//! |-- RiStr
-//! | `-- RiAbsoluteStr
-//! `-- RiRelativeStr
-//! ```
-//!
-//! Therefore, the conversions below are safe and cheap:
-//!
-//! * `RiStr -> RiReferenceStr`
-//! * `RiAbsoluteStr -> RiStr`
-//! * `RiAbsoluteStr -> RiReferenceStr`
-//! * `RiRelativeStr -> RiReferenceStr`
-//!
-//! For safely convertible types (consider `FooStr -> BarStr` is safe), traits
-//! below are implemented:
-//!
-//! * `AsRef<BarStr> for FooStr`
-//! * `AsRef<BarStr> for FooString`
-//! * `From<FooString> for BarString`
-//! * `PartialEq<FooStr> for BarStr` and lots of impls like that
-//! + `PartialEq` and `ParitalOrd`.
-//! + Slice, owned, `Cow`, reference, etc...
-
-pub use self::{
- absolute::RiAbsoluteStr, fragment::RiFragmentStr, normal::RiStr, query::RiQueryStr,
- reference::RiReferenceStr, relative::RiRelativeStr,
-};
-#[cfg(feature = "alloc")]
-pub use self::{
- absolute::RiAbsoluteString, error::CreationError, fragment::RiFragmentString, normal::RiString,
- query::RiQueryString, reference::RiReferenceString, relative::RiRelativeString,
-};
-
-#[macro_use]
-mod macros;
-
-mod absolute;
-#[cfg(feature = "alloc")]
-mod error;
-mod fragment;
-mod normal;
-mod query;
-mod reference;
-mod relative;
diff --git a/vendor/iri-string/src/types/generic/absolute.rs b/vendor/iri-string/src/types/generic/absolute.rs
deleted file mode 100644
index 8e588ede..00000000
--- a/vendor/iri-string/src/types/generic/absolute.rs
+++ /dev/null
@@ -1,728 +0,0 @@
-//! Absolute IRI (without fragment part).
-
-use crate::components::AuthorityComponents;
-#[cfg(feature = "alloc")]
-use crate::mask_password::password_range_to_hide;
-use crate::mask_password::PasswordMasked;
-use crate::normalize::{Error, NormalizationInput, Normalized, NormalizednessCheckMode};
-use crate::parser::trusted as trusted_parser;
-use crate::spec::Spec;
-use crate::types::{RiQueryStr, RiReferenceStr, RiStr};
-#[cfg(feature = "alloc")]
-use crate::types::{RiReferenceString, RiString};
-use crate::validate::absolute_iri;
-
-define_custom_string_slice! {
- /// A borrowed slice of an absolute IRI without fragment part.
- ///
- /// This corresponds to [`absolute-IRI` rule] in [RFC 3987]
- /// (and [`absolute-URI` rule] in [RFC 3986]).
- /// In other words, this is [`RiStr`] without fragment part.
- ///
- /// If you want to accept fragment part, use [`RiStr`].
- ///
- /// # Valid values
- ///
- /// This type can have an absolute IRI without fragment part.
- ///
- /// ```
- /// # use iri_string::types::IriAbsoluteStr;
- /// assert!(IriAbsoluteStr::new("https://example.com/foo?bar=baz").is_ok());
- /// assert!(IriAbsoluteStr::new("foo:bar").is_ok());
- /// // Scheme `foo` and empty path.
- /// assert!(IriAbsoluteStr::new("foo:").is_ok());
- /// // `foo://.../` below are all allowed. See the crate documentation for detail.
- /// assert!(IriAbsoluteStr::new("foo:/").is_ok());
- /// assert!(IriAbsoluteStr::new("foo://").is_ok());
- /// assert!(IriAbsoluteStr::new("foo:///").is_ok());
- /// assert!(IriAbsoluteStr::new("foo:////").is_ok());
- /// assert!(IriAbsoluteStr::new("foo://///").is_ok());
- ///
- /// ```
- ///
- /// Relative IRI is not allowed.
- ///
- /// ```
- /// # use iri_string::types::IriAbsoluteStr;
- /// // This is relative path.
- /// assert!(IriAbsoluteStr::new("foo/bar").is_err());
- /// // `/foo/bar` is an absolute path, but it is authority-relative.
- /// assert!(IriAbsoluteStr::new("/foo/bar").is_err());
- /// // `//foo/bar` is termed "network-path reference",
- /// // or usually called "protocol-relative reference".
- /// assert!(IriAbsoluteStr::new("//foo/bar").is_err());
- /// // Empty string is not a valid absolute IRI.
- /// assert!(IriAbsoluteStr::new("").is_err());
- /// ```
- ///
- /// Fragment part (such as trailing `#foo`) is not allowed.
- ///
- /// ```
- /// # use iri_string::types::IriAbsoluteStr;
- /// // Fragment part is not allowed.
- /// assert!(IriAbsoluteStr::new("https://example.com/foo?bar=baz#qux").is_err());
- /// ```
- ///
- /// Some characters and sequences cannot used in an absolute IRI.
- ///
- /// ```
- /// # use iri_string::types::IriAbsoluteStr;
- /// // `<` and `>` cannot directly appear in an absolute IRI.
- /// assert!(IriAbsoluteStr::new("<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in an absolute IRI.
- /// assert!(IriAbsoluteStr::new("%").is_err());
- /// assert!(IriAbsoluteStr::new("%GG").is_err());
- /// ```
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`absolute-IRI` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`absolute-URI` rule]: https://tools.ietf.org/html/rfc3986#section-4.3
- /// [`RiStr`]: struct.RiStr.html
- struct RiAbsoluteStr {
- validator = absolute_iri,
- expecting_msg = "Absolute IRI string",
- }
-}
-
-#[cfg(feature = "alloc")]
-define_custom_string_owned! {
- /// An owned string of an absolute IRI without fragment part.
- ///
- /// This corresponds to [`absolute-IRI` rule] in [RFC 3987]
- /// (and [`absolute-URI` rule] in [RFC 3986]).
- /// The rule for `absolute-IRI` is `scheme ":" ihier-part [ "?" iquery ]`.
- /// In other words, this is [`RiString`] without fragment part.
- ///
- /// If you want to accept fragment part, use [`RiString`].
- ///
- /// For details, see the document for [`RiAbsoluteStr`].
- ///
- /// Enabled by `alloc` or `std` feature.
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`absolute-IRI` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`absolute-URI` rule]: https://tools.ietf.org/html/rfc3986#section-4.3
- /// [`RiAbsoluteStr`]: struct.RiAbsoluteStr.html
- /// [`RiString`]: struct.RiString.html
- struct RiAbsoluteString {
- validator = absolute_iri,
- slice = RiAbsoluteStr,
- expecting_msg = "Absolute IRI string",
- }
-}
-
-impl<S: Spec> RiAbsoluteStr<S> {
- /// Returns Ok`(())` if the IRI is normalizable by the RFC 3986 algorithm.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("HTTP://example.COM/foo/%2e/bar/..")?;
- /// assert!(iri.ensure_rfc3986_normalizable().is_ok());
- ///
- /// let iri2 = IriAbsoluteStr::new("scheme:/..//bar")?;
- /// // The normalization result would be `scheme://bar` according to RFC
- /// // 3986, but it is unintended and should be treated as a failure.
- /// // This crate automatically handles this case so that `.normalize()` won't fail.
- /// assert!(!iri.ensure_rfc3986_normalizable().is_err());
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn ensure_rfc3986_normalizable(&self) -> Result<(), Error> {
- NormalizationInput::from(self).ensure_rfc3986_normalizable()
- }
-
- /// Returns `true` if the IRI is already normalized.
- ///
- /// This returns the same result as `self.normalize().to_string() == self`,
- /// but does this more efficiently without heap allocation.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query")?;
- /// assert!(!iri.is_normalized());
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query");
- /// assert!(normalized.is_normalized());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("scheme:/.///foo")?;
- /// // Already normalized.
- /// assert!(iri.is_normalized());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("scheme:relative/..//not-a-host")?;
- /// // Default normalization algorithm assumes the path part to be NOT opaque.
- /// assert!(!iri.is_normalized());
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "scheme:/.//not-a-host");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn is_normalized(&self) -> bool {
- trusted_parser::is_normalized::<S>(self.as_str(), NormalizednessCheckMode::Default)
- }
-
- /// Returns `true` if the IRI is already normalized.
- ///
- /// This returns the same result as
- /// `self.ensure_rfc3986_normalizable() && (self.normalize().to_string() == self)`,
- /// does this more efficiently without heap allocation.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query")?;
- /// assert!(!iri.is_normalized_rfc3986());
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query");
- /// assert!(normalized.is_normalized_rfc3986());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("scheme:/.///foo")?;
- /// // Not normalized in the sense of RFC 3986.
- /// assert!(!iri.is_normalized_rfc3986());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("scheme:relative/..//not-a-host")?;
- /// // RFC 3986 normalization algorithm assumes the path part to be NOT opaque.
- /// assert!(!iri.is_normalized_rfc3986());
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "scheme:/.//not-a-host");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn is_normalized_rfc3986(&self) -> bool {
- trusted_parser::is_normalized::<S>(self.as_str(), NormalizednessCheckMode::Rfc3986)
- }
-
- /// Returns `true` if the IRI is already normalized in the sense of
- /// [`normalize_but_preserve_authorityless_relative_path`] method.
- ///
- /// This returns the same result as
- /// `self.normalize_but_preserve_authorityless_relative_path().to_string() == self`,
- /// but does this more efficiently without heap allocation.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query")?;
- /// assert!(!iri.is_normalized_but_authorityless_relative_path_preserved());
- ///
- /// let normalized = iri
- /// .normalize_but_preserve_authorityless_relative_path()
- /// .to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query");
- /// assert!(normalized.is_normalized());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("scheme:/.///foo")?;
- /// // Already normalized in the sense of
- /// // `normalize_but_opaque_authorityless_relative_path()` method.
- /// assert!(iri.is_normalized_but_authorityless_relative_path_preserved());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("scheme:relative/..//not-a-host")?;
- /// // Relative path is treated as opaque since the autority component is absent.
- /// assert!(iri.is_normalized_but_authorityless_relative_path_preserved());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// [`normalize_but_preserve_authorityless_relative_path`]:
- /// `Self::normalize_but_preserve_authorityless_relative_path`
- #[inline]
- #[must_use]
- pub fn is_normalized_but_authorityless_relative_path_preserved(&self) -> bool {
- trusted_parser::is_normalized::<S>(
- self.as_str(),
- NormalizednessCheckMode::PreserveAuthoritylessRelativePath,
- )
- }
-
- /// Returns the normalized IRI.
- ///
- /// # Notes
- ///
- /// For some abnormal IRIs, the normalization can produce semantically
- /// incorrect string that looks syntactically valid. To avoid security
- /// issues by this trap, the normalization algorithm by this crate
- /// automatically applies the workaround.
- ///
- /// If you worry about this, test by
- /// [`RiAbsoluteStr::ensure_rfc3986_normalizable`] method or
- /// [`Normalized::ensure_rfc3986_normalizable`] before using the result
- /// string.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query")?;
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn normalize(&self) -> Normalized<'_, Self> {
- Normalized::from_input(NormalizationInput::from(self)).and_normalize()
- }
-
- /// Returns the normalized IRI, but preserving dot segments in relative path
- /// if the authority component is absent.
- ///
- /// This normalization would be similar to that of [WHATWG URL Standard]
- /// while this implementation is not guaranteed to stricly follow the spec.
- ///
- /// Note that this normalization algorithm is not compatible with RFC 3986
- /// algorithm for some inputs.
- ///
- /// Note that case normalization and percent-encoding normalization will
- /// still be applied to any path.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query")?;
- ///
- /// let normalized = iri
- /// .normalize_but_preserve_authorityless_relative_path()
- /// .to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("scheme:relative/../f%6f%6f")?;
- ///
- /// let normalized = iri
- /// .normalize_but_preserve_authorityless_relative_path()
- /// .to_dedicated_string();
- /// assert_eq!(normalized, "scheme:relative/../foo");
- /// // `.normalize()` would normalize this to `scheme:/foo`.
- /// # assert_eq!(iri.normalize().to_dedicated_string(), "scheme:/foo");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// [WHATWG URL Standard]: https://url.spec.whatwg.org/
- #[inline]
- #[must_use]
- pub fn normalize_but_preserve_authorityless_relative_path(&self) -> Normalized<'_, Self> {
- Normalized::from_input(NormalizationInput::from(self))
- .and_normalize_but_preserve_authorityless_relative_path()
- }
-
- /// Returns the proxy to the IRI with password masking feature.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("http://user:password@example.com/path?query")?;
- /// let masked = iri.mask_password();
- /// assert_eq!(masked.to_dedicated_string(), "http://user:@example.com/path?query");
- ///
- /// assert_eq!(
- /// masked.replace_password("${password}").to_string(),
- /// "http://user:${password}@example.com/path?query"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn mask_password(&self) -> PasswordMasked<'_, Self> {
- PasswordMasked::new(self)
- }
-}
-
-/// Components getters.
-impl<S: Spec> RiAbsoluteStr<S> {
- /// Returns the scheme.
- ///
- /// The following colon is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("http://example.com/pathpath?queryquery")?;
- /// assert_eq!(iri.scheme_str(), "http");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn scheme_str(&self) -> &str {
- trusted_parser::extract_scheme_absolute(self.as_str())
- }
-
- /// Returns the authority.
- ///
- /// The leading `//` is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("http://example.com/pathpath?queryquery")?;
- /// assert_eq!(iri.authority_str(), Some("example.com"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_str(&self) -> Option<&str> {
- trusted_parser::extract_authority_absolute(self.as_str())
- }
-
- /// Returns the path.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("http://example.com/pathpath?queryquery")?;
- /// assert_eq!(iri.path_str(), "/pathpath");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.path_str(), "uuid:10db315b-fcd1-4428-aca8-15babc9a2da2");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn path_str(&self) -> &str {
- trusted_parser::extract_path_absolute(self.as_str())
- }
-
- /// Returns the query.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::{IriAbsoluteStr, IriQueryStr};
- ///
- /// let iri = IriAbsoluteStr::new("http://example.com/pathpath?queryquery")?;
- /// let query = IriQueryStr::new("queryquery")?;
- /// assert_eq!(iri.query(), Some(query));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.query(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query(&self) -> Option<&RiQueryStr<S>> {
- trusted_parser::extract_query_absolute_iri(self.as_str()).map(|query| {
- // SAFETY: `trusted_parser::extract_query_absolute_iri()` must return
- // the query part of an IRI (including the leading `?` character),
- // and the returned string consists of allowed characters since it
- // is a substring of the source IRI.
- unsafe { RiQueryStr::new_maybe_unchecked(query) }
- })
- }
-
- /// Returns the query in a raw string slice.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("http://example.com/pathpath?queryquery")?;
- /// assert_eq!(iri.query_str(), Some("queryquery"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.query_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query_str(&self) -> Option<&str> {
- trusted_parser::extract_query_absolute_iri(self.as_str())
- }
-
- /// Returns the authority components.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("http://user:pass@example.com:8080/pathpath?queryquery")?;
- /// let authority = iri.authority_components()
- /// .expect("authority is available");
- /// assert_eq!(authority.userinfo(), Some("user:pass"));
- /// assert_eq!(authority.host(), "example.com");
- /// assert_eq!(authority.port(), Some("8080"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriAbsoluteStr;
- ///
- /// let iri = IriAbsoluteStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_components(&self) -> Option<AuthorityComponents<'_>> {
- AuthorityComponents::from_iri(self.as_ref())
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> RiAbsoluteString<S> {
- /// Removes the password completely (including separator colon) from `self` even if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriAbsoluteString;
- ///
- /// let mut iri = IriAbsoluteString::try_from("http://user:password@example.com/path?query")?;
- /// iri.remove_password_inline();
- /// assert_eq!(iri, "http://user@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// Even if the password is empty, the password and separator will be removed.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriAbsoluteString;
- ///
- /// let mut iri = IriAbsoluteString::try_from("http://user:@example.com/path?query")?;
- /// iri.remove_password_inline();
- /// assert_eq!(iri, "http://user@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn remove_password_inline(&mut self) {
- let pw_range = match password_range_to_hide(self.as_slice().as_ref()) {
- Some(v) => v,
- None => return,
- };
- let separator_colon = pw_range.start - 1;
- // SAFETY: the IRI must still be valid after the password component and
- // the leading separator colon is removed.
- unsafe {
- let buf = self.as_inner_mut();
- buf.drain(separator_colon..pw_range.end);
- debug_assert!(
- RiAbsoluteStr::<S>::new(buf).is_ok(),
- "[validity] the IRI must be valid after the password component is removed"
- );
- }
- }
-
- /// Replaces the non-empty password in `self` to the empty password.
- ///
- /// This leaves the separator colon if the password part was available.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriAbsoluteString;
- ///
- /// let mut iri = IriAbsoluteString::try_from("http://user:password@example.com/path?query")?;
- /// iri.remove_nonempty_password_inline();
- /// assert_eq!(iri, "http://user:@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the password is empty, it is left as is.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriAbsoluteString;
- ///
- /// let mut iri = IriAbsoluteString::try_from("http://user:@example.com/path?query")?;
- /// iri.remove_nonempty_password_inline();
- /// assert_eq!(iri, "http://user:@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn remove_nonempty_password_inline(&mut self) {
- let pw_range = match password_range_to_hide(self.as_slice().as_ref()) {
- Some(v) if !v.is_empty() => v,
- _ => return,
- };
- debug_assert_eq!(
- self.as_str().as_bytes().get(pw_range.start - 1).copied(),
- Some(b':'),
- "[validity] the password component must be prefixed with a separator colon"
- );
- // SAFETY: the IRI must be valid after the password is replaced with empty string.
- unsafe {
- let buf = self.as_inner_mut();
- buf.drain(pw_range);
- debug_assert!(
- RiAbsoluteStr::<S>::new(buf).is_ok(),
- "[validity] the IRI must be valid after the password component is removed"
- );
- }
- }
-}
-
-impl_trivial_conv_between_iri! {
- from_slice: RiAbsoluteStr,
- from_owned: RiAbsoluteString,
- to_slice: RiStr,
- to_owned: RiString,
-}
-
-impl_trivial_conv_between_iri! {
- from_slice: RiAbsoluteStr,
- from_owned: RiAbsoluteString,
- to_slice: RiReferenceStr,
- to_owned: RiReferenceString,
-}
diff --git a/vendor/iri-string/src/types/generic/error.rs b/vendor/iri-string/src/types/generic/error.rs
deleted file mode 100644
index b11f58b2..00000000
--- a/vendor/iri-string/src/types/generic/error.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-//! Resource identifier creation error.
-
-use core::fmt;
-
-#[cfg(feature = "std")]
-use std::error;
-
-use crate::validate::Error;
-
-/// Error on conversion into an IRI type.
-///
-/// Enabled by `alloc` or `std` feature.
-// This type itself does not require `alloc` or `std, but the type is used only when `alloc`
-// feature is enabled. To avoid exporting unused stuff, the type (and the `types::generic::error`
-// module) is available only when necessary.
-//
-// Note that all types which implement `Spec` also implement `SpecInternal`.
-pub struct CreationError<T> {
- /// Soruce data.
- source: T,
- /// Validation error.
- error: Error,
-}
-
-impl<T> CreationError<T> {
- /// Returns the source data.
- #[must_use]
- pub fn into_source(self) -> T {
- self.source
- }
-
- /// Returns the validation error.
- #[must_use]
- pub fn validation_error(&self) -> Error {
- self.error
- }
-
- /// Creates a new `CreationError`.
- #[must_use]
- pub(crate) fn new(error: Error, source: T) -> Self {
- Self { source, error }
- }
-}
-
-impl<T: fmt::Debug> fmt::Debug for CreationError<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("CreationError")
- .field("source", &self.source)
- .field("error", &self.error)
- .finish()
- }
-}
-
-impl<T: Clone> Clone for CreationError<T> {
- fn clone(&self) -> Self {
- Self {
- source: self.source.clone(),
- error: self.error,
- }
- }
-}
-
-impl<T> fmt::Display for CreationError<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.error.fmt(f)
- }
-}
-
-#[cfg(feature = "std")]
-impl<T: fmt::Debug> error::Error for CreationError<T> {}
diff --git a/vendor/iri-string/src/types/generic/fragment.rs b/vendor/iri-string/src/types/generic/fragment.rs
deleted file mode 100644
index 2fdc1613..00000000
--- a/vendor/iri-string/src/types/generic/fragment.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-//! Fragment string.
-
-use crate::{
- spec::Spec,
- validate::{fragment, Error},
-};
-
-define_custom_string_slice! {
- /// A borrowed slice of an IRI fragment (i.e. after the first `#` character).
- ///
- /// This corresponds to [`ifragment` rule] in [RFC 3987] (and [`fragment` rule] in [RFC 3986]).
- /// The rule for `ifragment` is `*( ipchar / "/" / "?" )`.
- ///
- /// # Valid values
- ///
- /// This type can have an IRI fragment.
- /// Note that the IRI `foo://bar/baz#qux` has the fragment `qux`, **not** `#qux`.
- ///
- /// ```
- /// # use iri_string::types::IriFragmentStr;
- /// assert!(IriFragmentStr::new("").is_ok());
- /// assert!(IriFragmentStr::new("foo").is_ok());
- /// assert!(IriFragmentStr::new("foo/bar").is_ok());
- /// assert!(IriFragmentStr::new("/foo/bar").is_ok());
- /// assert!(IriFragmentStr::new("//foo/bar").is_ok());
- /// assert!(IriFragmentStr::new("https://user:pass@example.com:8080").is_ok());
- /// assert!(IriFragmentStr::new("https://example.com/").is_ok());
- /// ```
- ///
- /// Some characters and sequences cannot used in a fragment.
- ///
- /// ```
- /// # use iri_string::types::IriFragmentStr;
- /// // `<` and `>` cannot directly appear in an IRI reference.
- /// assert!(IriFragmentStr::new("<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in an IRI reference.
- /// assert!(IriFragmentStr::new("%").is_err());
- /// assert!(IriFragmentStr::new("%GG").is_err());
- /// // Hash sign `#` cannot appear in an IRI fragment.
- /// assert!(IriFragmentStr::new("#hash").is_err());
- /// ```
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`fragment` rule]: https://tools.ietf.org/html/rfc3986#section-3.5
- /// [`ifragment` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- struct RiFragmentStr {
- validator = fragment,
- expecting_msg = "IRI fragment string",
- }
-}
-
-#[cfg(feature = "alloc")]
-define_custom_string_owned! {
- /// An owned string of an IRI fragment (i.e. after the first `#` character).
- ///
- /// This corresponds to [`ifragment` rule] in [RFC 3987] (and [`fragment` rule] in [RFC 3986]).
- /// The rule for `absolute-IRI` is `*( ipchar / "/" / "?" )`.
- ///
- /// For details, see the documentation for [`RiFragmentStr`].
- ///
- /// Enabled by `alloc` or `std` feature.
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`fragment` rule]: https://tools.ietf.org/html/rfc3986#section-3.5
- /// [`ifragment` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`RiFragmentStr`]: struct.RiFragmentStr.html
- struct RiFragmentString {
- validator = fragment,
- slice = RiFragmentStr,
- expecting_msg = "IRI fragment string",
- }
-}
-
-impl<S: Spec> RiFragmentStr<S> {
- /// Creates a new `&RiFragmentStr` from the fragment part prefixed by `#`.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::types::IriFragmentStr;
- /// assert!(IriFragmentStr::from_prefixed("#").is_ok());
- /// assert!(IriFragmentStr::from_prefixed("#foo").is_ok());
- /// assert!(IriFragmentStr::from_prefixed("#foo/bar").is_ok());
- /// assert!(IriFragmentStr::from_prefixed("#/foo/bar").is_ok());
- /// assert!(IriFragmentStr::from_prefixed("#//foo/bar").is_ok());
- /// assert!(IriFragmentStr::from_prefixed("#https://user:pass@example.com:8080").is_ok());
- /// assert!(IriFragmentStr::from_prefixed("#https://example.com/").is_ok());
- ///
- /// // `<` and `>` cannot directly appear in an IRI.
- /// assert!(IriFragmentStr::from_prefixed("#<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in an IRI.
- /// assert!(IriFragmentStr::new("#%").is_err());
- /// assert!(IriFragmentStr::new("#%GG").is_err());
- /// // `#` prefix is expected.
- /// assert!(IriFragmentStr::from_prefixed("").is_err());
- /// assert!(IriFragmentStr::from_prefixed("foo").is_err());
- /// // Hash sign `#` cannot appear in an IRI fragment.
- /// assert!(IriFragmentStr::from_prefixed("##hash").is_err());
- /// ```
- pub fn from_prefixed(s: &str) -> Result<&Self, Error> {
- if !s.starts_with('#') {
- return Err(Error::new());
- }
- TryFrom::try_from(&s[1..])
- }
-}
diff --git a/vendor/iri-string/src/types/generic/macros.rs b/vendor/iri-string/src/types/generic/macros.rs
deleted file mode 100644
index 7aaa82df..00000000
--- a/vendor/iri-string/src/types/generic/macros.rs
+++ /dev/null
@@ -1,1041 +0,0 @@
-//! Macros to define resource identifier types.
-
-/// Implements type conversion from slice into smart pointer.
-macro_rules! impl_from_slice_into_smartptr {
- (
- // Generic slice type.
- ty: $ty:ident,
- // Smart pointer item path (without type parameter).
- smartptr: $($smartptr:ident)::*,
- // Pointer mutability for `into_raw` and `from_raw`.
- // Use `mut` for `Box`, and `const` for `Arc` and `Rc`.
- mutability: $mut:ident,
- ) => {
- #[cfg(feature = "alloc")]
- impl<S: crate::spec::Spec> From<&$ty<S>> for $($smartptr)::* <$ty<S>> {
- fn from(s: &$ty<S>) -> Self {
- let inner: &str = s.as_str();
- let buf = $($smartptr)::* ::<str>::from(inner);
- // SAFETY: `$ty<S>` has `repr(transparent)` attribute, so the
- // memory layouts of `$smartptr<str>` and `$smartptr<$ty<S>>`
- // are compatible.
- unsafe {
- let raw: *$mut str = $($smartptr)::* ::into_raw(buf);
- $($smartptr)::* ::<$ty<S>>::from_raw(raw as *$mut $ty<S>)
- }
- }
- }
- };
-}
-
-/// Implements `PartialEq` and `PartialOrd`.
-macro_rules! impl_cmp {
- ($ty_common:ty, $ty_lhs:ty, $ty_rhs:ty) => {
- impl<S: crate::spec::Spec> PartialEq<$ty_rhs> for $ty_lhs {
- #[inline]
- fn eq(&self, o: &$ty_rhs) -> bool {
- <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
- }
- }
- impl<S: crate::spec::Spec> PartialEq<$ty_lhs> for $ty_rhs {
- #[inline]
- fn eq(&self, o: &$ty_lhs) -> bool {
- <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
- }
- }
- impl<S: crate::spec::Spec> PartialOrd<$ty_rhs> for $ty_lhs {
- #[inline]
- fn partial_cmp(&self, o: &$ty_rhs) -> Option<core::cmp::Ordering> {
- <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
- }
- }
- impl<S: crate::spec::Spec> PartialOrd<$ty_lhs> for $ty_rhs {
- #[inline]
- fn partial_cmp(&self, o: &$ty_lhs) -> Option<core::cmp::Ordering> {
- <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
- }
- }
- };
-}
-
-/// Implements `PartialEq` and `PartialOrd` with two independent spec type parameter.
-macro_rules! impl_cmp2 {
- ($ty_common:ty, $ty_lhs:ty, $ty_rhs:ty) => {
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty_rhs> for $ty_lhs {
- #[inline]
- fn eq(&self, o: &$ty_rhs) -> bool {
- <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
- }
- }
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty_lhs> for $ty_rhs {
- #[inline]
- fn eq(&self, o: &$ty_lhs) -> bool {
- <$ty_common as PartialEq<$ty_common>>::eq(self.as_ref(), o.as_ref())
- }
- }
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty_rhs> for $ty_lhs {
- #[inline]
- fn partial_cmp(&self, o: &$ty_rhs) -> Option<core::cmp::Ordering> {
- <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
- }
- }
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty_lhs> for $ty_rhs {
- #[inline]
- fn partial_cmp(&self, o: &$ty_lhs) -> Option<core::cmp::Ordering> {
- <$ty_common as PartialOrd<$ty_common>>::partial_cmp(self.as_ref(), o.as_ref())
- }
- }
- };
-}
-
-/// Implements `PartialEq` and `PartialOrd` with two independent spec type parameter.
-macro_rules! impl_cmp2_as_str {
- ($ty_lhs:ty, $ty_rhs:ty) => {
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty_rhs> for $ty_lhs {
- #[inline]
- fn eq(&self, o: &$ty_rhs) -> bool {
- PartialEq::eq(self.as_str(), o.as_str())
- }
- }
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty_lhs> for $ty_rhs {
- #[inline]
- fn eq(&self, o: &$ty_lhs) -> bool {
- PartialEq::eq(self.as_str(), o.as_str())
- }
- }
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty_rhs> for $ty_lhs {
- #[inline]
- fn partial_cmp(&self, o: &$ty_rhs) -> Option<core::cmp::Ordering> {
- PartialOrd::partial_cmp(self.as_str(), o.as_str())
- }
- }
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty_lhs> for $ty_rhs {
- #[inline]
- fn partial_cmp(&self, o: &$ty_lhs) -> Option<core::cmp::Ordering> {
- PartialOrd::partial_cmp(self.as_str(), o.as_str())
- }
- }
- };
-}
-
-/// Define the custom string slice type, and implements methods and traits.
-///
-/// Methods to be implemented:
-///
-/// * `pub fn new()`
-/// * `pub fn new_unchecked()`
-/// * `pub(crate) fn new_maybe_unchecked()`
-/// * `fn new_always_unchecked()`
-/// * `pub fn as_str()`
-/// * `pub fn len()`
-/// * `pub fn is_empty()`
-///
-/// Traits to be implemented:
-///
-/// * fundamental
-/// + `Debug for $ty`
-/// + `Eq for $ty`
-/// + `Ord for $ty`
-/// + `Hash for $ty`
-/// * type conversion
-/// + `AsRef<&str> for $ty`
-/// + `AsRef<&$ty> for $ty`
-/// + `From<&$ty>` for Cow<$ty>`
-/// + `From<&$ty>` for Arc<$ty>`
-/// + `From<&$ty>` for Box<$ty>`
-/// + `From<&$ty>` for Rc<$ty>`
-/// + `From<&$ty> for &str`
-/// + `TryFrom<&str> for &$ty`
-/// + `TryFrom<&[u8]> for &$ty`
-/// * comparison (only `PartialEq` impls are listed, but `PartialOrd` is also implemented).
-/// + `PartialEq<$ty> for $ty`
-/// + `str` and `$ty`
-/// - `PartialEq<str> for $ty`
-/// - `PartialEq<$ty> for str`
-/// - `PartialEq<&str> for $ty`
-/// - `PartialEq<$ty> for &str`
-/// - `PartialEq<str> for &$ty`
-/// - `PartialEq<&$ty> for str`
-/// + `$ty` and `$ty`
-/// - `PartialEq<&$ty> for $ty`
-/// - `PartialEq<$ty> for &$ty`
-/// * other
-/// + `Display for $ty`
-/// * serde
-/// + `serde::Serialize`
-/// + `serde::Deserialize`
-macro_rules! define_custom_string_slice {
- (
- $(#[$meta:meta])*
- struct $ty:ident {
- validator = $validate:ident,
- expecting_msg = $expecting:expr,
- }
- ) => {
- $(#[$meta])*
- // `#[derive(..)]` cannot be used here, because it adds `S: DerivedTrait` bounds automatically.
- #[repr(transparent)]
- #[cfg_attr(feature = "serde", derive(serde::Serialize))]
- #[cfg_attr(feature = "serde", serde(bound = "S: crate::spec::Spec"))]
- #[cfg_attr(feature = "serde", serde(transparent))]
- pub struct $ty<S> {
- /// Spec.
- #[cfg_attr(feature = "serde", serde(skip))]
- _spec: core::marker::PhantomData<fn() -> S>,
- /// Inner data.
- inner: str,
- }
-
- impl<S: crate::spec::Spec> $ty<S> {
- /// Creates a new string.
- #[inline]
- pub fn new(s: &str) -> Result<&Self, crate::validate::Error> {
- core::convert::TryFrom::try_from(s)
- }
-
- /// Creates a new string without validation.
- ///
- /// This does not validate the given string, so it is caller's
- /// responsibility to ensure the given string is valid.
- ///
- /// # Safety
- ///
- /// The given string must be syntactically valid as `Self` type.
- /// If not, any use of the returned value or the call of this
- /// function itself may result in undefined behavior.
- #[inline]
- #[must_use]
- pub unsafe fn new_unchecked(s: &str) -> &Self {
- // SAFETY: `new_always_unchecked` requires the same precondition
- // as `new_always_unchecked`.
- unsafe { Self::new_always_unchecked(s) }
- }
-
- /// Creates a new string maybe without validation.
- ///
- /// This does validation on debug build.
- ///
- /// # Safety
- ///
- /// The given string must be syntactically valid as `Self` type.
- #[must_use]
- pub(crate) unsafe fn new_maybe_unchecked(s: &str) -> &Self {
- debug_assert_eq!($validate::<S>(s), Ok(()));
- // SAFETY: `new_always_unchecked` requires the same precondition
- // as `new_always_unchecked`. Additionally in debug build, just
- // checked the content is actually valid by `$validate::<S>(s)`.
- unsafe { Self::new_always_unchecked(s) }
- }
-
- /// Creates a new string without any validation.
- ///
- /// This does not validate the given string at any time.
- ///
- /// Intended for internal use.
- ///
- /// # Safety
- ///
- /// The given string must be syntactically valid as `Self` type.
- #[inline]
- #[must_use]
- unsafe fn new_always_unchecked(s: &str) -> &Self {
- // SAFETY: the cast is safe since `Self` type has `repr(transparent)`
- // attribute and the content is guaranteed as valid by the
- // precondition of the function.
- unsafe { &*(s as *const str as *const Self) }
- }
-
- /// Returns `&str`.
- #[inline]
- #[must_use]
- pub fn as_str(&self) -> &str {
- self.as_ref()
- }
-
- /// Returns the string length.
- #[inline]
- #[must_use]
- pub fn len(&self) -> usize {
- self.as_str().len()
- }
-
- /// Returns whether the string is empty.
- #[inline]
- #[must_use]
- pub fn is_empty(&self) -> bool {
- self.as_str().is_empty()
- }
- }
-
- impl<S: crate::spec::Spec> core::fmt::Debug for $ty<S> {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_tuple(stringify!($ty)).field(&&self.inner).finish()
- }
- }
-
- impl<S: crate::spec::Spec> PartialEq for $ty<S> {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner == other.inner
- }
- }
-
- impl<S: crate::spec::Spec> Eq for $ty<S> {}
-
- impl<S: crate::spec::Spec> PartialOrd for $ty<S> {
- #[inline]
- fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
- Some(self.inner.cmp(&other.inner))
- }
- }
-
- impl<S: crate::spec::Spec> Ord for $ty<S> {
- #[inline]
- fn cmp(&self, other: &Self) -> core::cmp::Ordering {
- self.inner.cmp(&other.inner)
- }
- }
-
- impl<S: crate::spec::Spec> core::hash::Hash for $ty<S> {
- #[inline]
- fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
- self.inner.hash(state);
- }
- }
-
- impl<S: crate::spec::Spec> AsRef<str> for $ty<S> {
- #[inline]
- fn as_ref(&self) -> &str {
- &self.inner
- }
- }
-
- impl<S: crate::spec::Spec> AsRef<$ty<S>> for $ty<S> {
- #[inline]
- fn as_ref(&self) -> &$ty<S> {
- self
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<'a, S: crate::spec::Spec> From<&'a $ty<S>> for alloc::borrow::Cow<'a, $ty<S>> {
- #[inline]
- fn from(s: &'a $ty<S>) -> Self {
- alloc::borrow::Cow::Borrowed(s)
- }
- }
-
- impl_from_slice_into_smartptr! {
- ty: $ty,
- smartptr: alloc::sync::Arc,
- mutability: const,
- }
-
- impl_from_slice_into_smartptr! {
- ty: $ty,
- smartptr: alloc::boxed::Box,
- mutability: mut,
- }
-
- impl_from_slice_into_smartptr! {
- ty: $ty,
- smartptr: alloc::rc::Rc,
- mutability: const,
- }
-
- impl<'a, S: crate::spec::Spec> From<&'a $ty<S>> for &'a str {
- #[inline]
- fn from(s: &'a $ty<S>) -> &'a str {
- s.as_ref()
- }
- }
-
- impl<'a, S: crate::spec::Spec> core::convert::TryFrom<&'a str> for &'a $ty<S> {
- type Error = crate::validate::Error;
-
- #[inline]
- fn try_from(s: &'a str) -> Result<Self, Self::Error> {
- match $validate::<S>(s) {
- // SAFETY: just checked `s` is valid as `$ty`.
- Ok(()) => Ok(unsafe { $ty::new_always_unchecked(s) }),
- Err(e) => Err(e),
- }
- }
- }
-
- impl<'a, S: crate::spec::Spec> core::convert::TryFrom<&'a [u8]> for &'a $ty<S> {
- type Error = crate::validate::Error;
-
- #[inline]
- fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
- let s = core::str::from_utf8(bytes).map_err(|_| crate::validate::Error::new())?;
- match $validate::<S>(s) {
- // SAFETY: just checked `s` is valid as `$ty`.
- Ok(()) => Ok(unsafe { $ty::new_always_unchecked(s) }),
- Err(e) => Err(e),
- }
- }
- }
-
- impl_cmp!(str, str, $ty<S>);
- impl_cmp!(str, &str, $ty<S>);
- impl_cmp!(str, str, &$ty<S>);
- impl_cmp2!(str, &$ty<S>, $ty<T>);
-
- impl<S: crate::spec::Spec> core::fmt::Display for $ty<S> {
- #[inline]
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.write_str(self.as_str())
- }
- }
-
- /// Serde deserializer implementation.
- #[cfg(feature = "serde")]
- mod __serde_slice {
- use super::$ty;
-
- use core::{convert::TryFrom, fmt, marker::PhantomData};
-
- use serde::{
- de::{self, Visitor},
- Deserialize, Deserializer,
- };
-
- /// Custom borrowed string visitor.
- #[derive(Debug, Clone, Copy)]
- struct CustomStrVisitor<S>(PhantomData<fn() -> S>);
-
- impl<'de, S: 'de + crate::spec::Spec> Visitor<'de> for CustomStrVisitor<S> {
- type Value = &'de $ty<S>;
-
- #[inline]
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str($expecting)
- }
-
- #[inline]
- fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- <&'de $ty<S> as TryFrom<&'de str>>::try_from(v).map_err(E::custom)
- }
- }
-
- // About `'de` and `'a`, see
- // <https://serde.rs/lifetimes.html#the-deserializede-lifetime>.
- impl<'de: 'a, 'a, S: 'de + crate::spec::Spec> Deserialize<'de> for &'a $ty<S> {
- #[inline]
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- deserializer.deserialize_string(CustomStrVisitor::<S>(PhantomData))
- }
- }
- }
- };
-}
-
-/// Define the custom owned string type, and implements methods and traits.
-///
-/// Methods to be implemented:
-///
-/// * `pub fn new_unchecked()`
-/// * `pub(crate) fn new_maybe_unchecked()`
-/// * `pub(crate) fn new_always_unchecked()`
-/// * `pub fn shrink_to_fit()`
-///
-/// Traits to be implemented:
-///
-/// * fundamental
-/// + `Debug for $ty`
-/// + `Clone for $ty`
-/// + `Eq for $ty`
-/// + `Ord for $ty`
-/// + `Hash for $ty`
-/// * type conversion
-/// + `AsRef<str> for $ty`
-/// + `AsRef<$slice> for $ty`
-/// + `Borrow<str> for $ty`
-/// + `Borrow<$slice> for $ty`
-/// + `ToOwned<Owned = $ty> for $slice`
-/// + `From<&$slice> for $ty`
-/// + `From<$ty> for String`
-/// + `From<$ty> for Cow<'_, $slice>`
-/// + `From<$ty> for Box<$slice>`
-/// + `TryFrom<&str> for $ty`
-/// + `TryFrom<&[u8]> for $ty`
-/// + `TryFrom<String> for $ty`
-/// + `FromStr for $ty`
-/// + `Deref<Target = $slice> for $ty`
-/// * comparison (only `PartialEq` impls are listed, but `PartialOrd` is also implemented.
-/// + `PartialEq<$ty> for $ty`
-/// + `$slice` and `str`
-/// - `PartialEq<$slice> for Cow<'_, str>`
-/// - `PartialEq<Cow<'_, str>> for $slice`
-/// - `PartialEq<&$slice> for Cow<'_, str>`
-/// - `PartialEq<Cow<'_, str>> for &$slice`
-/// + `$slice` and `Cow<$slice>`
-/// - `PartialEq<$slice> for Cow<'_, $slice>`
-/// - `PartialEq<Cow<'_, $slice>> for $slice`
-/// - `PartialEq<&$slice> for Cow<'_, $slice>`
-/// - `PartialEq<Cow<'_, $slice>> for &$slice`
-/// + `str` and `$ty`
-/// - `PartialEq<str> for $ty`
-/// - `PartialEq<$ty> for str`
-/// - `PartialEq<&str> for $ty`
-/// - `PartialEq<$ty> for &str`
-/// - `PartialEq<Cow<'_, str>> for $ty`
-/// - `PartialEq<$ty> for Cow<'_, str>`
-/// + `String` and `$ty`
-/// - `PartialEq<String> for $ty`
-/// - `PartialEq<$ty> for String`
-/// + `$slice` and `$ty`
-/// - `PartialEq<$slice> for $ty`
-/// - `PartialEq<$ty> for $slice`
-/// - `PartialEq<&$slice> for $ty`
-/// - `PartialEq<$ty> for &$slice`
-/// - `PartialEq<Cow<'_, $slice>> for $ty`
-/// - `PartialEq<$ty> for Cow<'_, $slice>`
-/// * other
-/// + `Display for $ty`
-/// * serde
-/// + `serde::Serialize`
-/// + `serde::Deserialize`
-// Note that `From<$ty> for {Arc,Rc}<$slice>` is currently not implemented since
-// this won't reuse allocated memory and hides internal memory reallocation. See
-// <https://github.com/lo48576/iri-string/issues/20#issuecomment-1105207849>.
-// However, this is not decided with firm belief or opinion, so there would be
-// a chance that they are implemented in future.
-#[cfg(feature = "alloc")]
-macro_rules! define_custom_string_owned {
- (
- $(#[$meta:meta])*
- struct $ty:ident {
- validator = $validate:ident,
- slice = $slice:ident,
- expecting_msg = $expecting:expr,
- }
- ) => {
- $(#[$meta])*
- // `#[derive(..)]` cannot be used here, because it adds `S: DerivedTrait` bounds automatically.
- #[cfg(feature = "alloc")]
- #[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize))]
- #[cfg_attr(all(feature = "serde", feature = "alloc"), serde(bound = "S: crate::spec::Spec"))]
- #[cfg_attr(all(feature = "serde", feature = "alloc"), serde(transparent))]
- pub struct $ty<S> {
- /// Spec.
- #[cfg_attr(all(feature = "serde", feature = "alloc"), serde(skip))]
- _spec: core::marker::PhantomData<fn() -> S>,
- /// Inner data.
- inner: alloc::string::String,
- }
-
- impl<S: crate::spec::Spec> $ty<S> {
- /// Creates a new string without validation.
- ///
- /// This does not validate the given string, so it is caller's
- /// responsibility to ensure the given string is valid.
- ///
- /// # Safety
- ///
- /// The given string must be syntactically valid as `Self` type.
- /// If not, any use of the returned value or the call of this
- /// function itself may result in undefined behavior.
- #[inline]
- #[must_use]
- pub unsafe fn new_unchecked(s: alloc::string::String) -> Self {
- // SAFETY: `new_always_unchecked` requires the same precondition
- // as `new_always_unchecked`.
- unsafe { Self::new_always_unchecked(s) }
- }
-
- /// Creates a new string maybe without validation.
- ///
- /// This does not validate the given string at any time.
- ///
- /// Intended for internal use.
- ///
- /// # Safety
- ///
- /// The given string must be syntactically valid as `Self` type.
- #[inline]
- #[must_use]
- pub(crate) unsafe fn new_always_unchecked(s: alloc::string::String) -> Self {
- // The construction itself can be written in safe Rust, but
- // every other place including unsafe functions expects
- // `self.inner` to be syntactically valid as `Self`. In order to
- // make them safe, the construction should validate the value
- // or at least should require users to validate the value by
- // making the function `unsafe`.
- Self {
- _spec: core::marker::PhantomData,
- inner: s,
- }
- }
-
- /// Creates a new string maybe without validation.
- ///
- /// This does validation on debug build.
- ///
- /// # Safety
- ///
- /// The given string must be syntactically valid as `Self` type.
- #[must_use]
- pub(crate) unsafe fn new_maybe_unchecked(s: alloc::string::String) -> Self {
- debug_assert_eq!(
- $validate::<S>(&s),
- Ok(()),
- "[precondition] the given string must be valid"
- );
- // SAFETY: `new_always_unchecked` requires the same precondition
- // as `new_always_unchecked`. Additionally in debug build, just
- // checked the content is actually valid by `$validate::<S>(s)`.
- unsafe { Self::new_always_unchecked(s) }
- }
-
- /// Returns a mutable reference to the inner string buffer.
- ///
- /// This may be useful to implement inline modification algorithm,
- /// but be careful as this method itself cannot validate the new
- /// content.
- ///
- /// # Safety
- ///
- /// The content after modification must be syntactically valid as
- /// `Self` type.
- /// If not, any use of the returned value or the call of this
- /// function itself may result in undefined behavior.
- #[inline]
- #[must_use]
- // TODO: Use wrapper type to enforce validation on finish?
- pub(crate) unsafe fn as_inner_mut(&mut self) -> &mut alloc::string::String {
- &mut self.inner
- }
-
- /// Shrinks the capacity of the inner buffer to match its length.
- #[inline]
- pub fn shrink_to_fit(&mut self) {
- self.inner.shrink_to_fit()
- }
-
- /// Returns the internal buffer capacity in bytes.
- #[inline]
- #[must_use]
- pub fn capacity(&self) -> usize {
- self.inner.capacity()
- }
-
- /// Returns the borrowed IRI string slice.
- ///
- /// This is equivalent to `&*self`.
- #[inline]
- #[must_use]
- pub fn as_slice(&self) -> &$slice<S> {
- self.as_ref()
- }
- }
-
- impl<S: crate::spec::Spec> core::fmt::Debug for $ty<S> {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_tuple(stringify!($ty)).field(&&self.inner).finish()
- }
- }
-
- impl<S: crate::spec::Spec> Clone for $ty<S> {
- #[inline]
- fn clone(&self) -> Self {
- // This is safe because `self` must be valid.
- Self {
- _spec: core::marker::PhantomData,
- inner: self.inner.clone(),
- }
- }
- }
-
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialEq<$ty<T>> for $ty<S> {
- #[inline]
- fn eq(&self, other: &$ty<T>) -> bool {
- self.inner == other.inner
- }
- }
-
- impl<S: crate::spec::Spec> Eq for $ty<S> {}
-
- impl<S: crate::spec::Spec, T: crate::spec::Spec> PartialOrd<$ty<T>> for $ty<S> {
- #[inline]
- fn partial_cmp(&self, other: &$ty<T>) -> Option<core::cmp::Ordering> {
- self.inner.partial_cmp(&other.inner)
- }
- }
-
- impl<S: crate::spec::Spec> Ord for $ty<S> {
- #[inline]
- fn cmp(&self, other: &Self) -> core::cmp::Ordering {
- self.inner.cmp(&other.inner)
- }
- }
-
- impl<S: crate::spec::Spec> core::hash::Hash for $ty<S> {
- #[inline]
- fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
- self.inner.hash(state);
- }
- }
-
- impl<S: crate::spec::Spec> AsRef<str> for $ty<S> {
- #[inline]
- fn as_ref(&self) -> &str {
- &self.inner
- }
- }
-
- impl<S: crate::spec::Spec> AsRef<$slice<S>> for $ty<S> {
- #[inline]
- fn as_ref(&self) -> &$slice<S> {
- // SAFETY: `$ty<S>` and `$slice<S>` requires same validation, so
- // the content of `self: &$ty<S>` must be valid as `$slice<S>`.
- unsafe { $slice::new_always_unchecked(AsRef::<str>::as_ref(self)) }
- }
- }
-
- impl<S: crate::spec::Spec> core::borrow::Borrow<str> for $ty<S> {
- #[inline]
- fn borrow(&self) -> &str {
- self.as_ref()
- }
- }
-
- impl<S: crate::spec::Spec> core::borrow::Borrow<$slice<S>> for $ty<S> {
- #[inline]
- fn borrow(&self) -> &$slice<S> {
- self.as_ref()
- }
- }
-
- impl<S: crate::spec::Spec> alloc::borrow::ToOwned for $slice<S> {
- type Owned = $ty<S>;
-
- #[inline]
- fn to_owned(&self) -> Self::Owned {
- self.into()
- }
- }
-
- impl<S: crate::spec::Spec> From<&'_ $slice<S>> for $ty<S> {
- #[inline]
- fn from(s: &$slice<S>) -> Self {
- // This is safe because `s` must be valid.
- $ty {
- _spec: core::marker::PhantomData,
- inner: alloc::string::String::from(s.as_str()),
- }
- }
- }
-
- impl<S: crate::spec::Spec> From<$ty<S>> for alloc::string::String {
- #[inline]
- fn from(s: $ty<S>) -> Self {
- s.inner
- }
- }
-
- impl<'a, S: crate::spec::Spec> From<$ty<S>> for alloc::borrow::Cow<'a, $slice<S>> {
- #[inline]
- fn from(s: $ty<S>) -> alloc::borrow::Cow<'a, $slice<S>> {
- alloc::borrow::Cow::Owned(s)
- }
- }
-
- impl<S: crate::spec::Spec> From<$ty<S>> for alloc::boxed::Box<$slice<S>> {
- #[inline]
- fn from(s: $ty<S>) -> alloc::boxed::Box<$slice<S>> {
- let inner: alloc::string::String = s.into();
- let buf = alloc::boxed::Box::<str>::from(inner);
- // SAFETY: `$slice<S>` has `repr(transparent)` attribute, so
- // the memory layouts of `Box<str>` and `Box<$slice<S>>` are
- // compatible. Additionally, `$ty<S>` and `$slice<S>` require
- // the same syntax (it is the macro user's responsibility to
- // guarantee).
- unsafe {
- let raw: *mut str = alloc::boxed::Box::into_raw(buf);
- alloc::boxed::Box::<$slice<S>>::from_raw(raw as *mut $slice<S>)
- }
- }
- }
-
- impl<S: crate::spec::Spec> core::convert::TryFrom<&'_ str> for $ty<S> {
- type Error = crate::validate::Error;
-
- #[inline]
- fn try_from(s: &str) -> Result<Self, Self::Error> {
- <&$slice<S>>::try_from(s).map(Into::into)
- }
- }
-
- impl<S: crate::spec::Spec> core::convert::TryFrom<&'_ [u8]> for $ty<S> {
- type Error = crate::validate::Error;
-
- #[inline]
- fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
- let s = core::str::from_utf8(bytes).map_err(|_| crate::validate::Error::new())?;
- <&$slice<S>>::try_from(s).map(Into::into)
- }
- }
-
- impl<S: crate::spec::Spec> core::convert::TryFrom<alloc::string::String> for $ty<S> {
- type Error = crate::types::CreationError<alloc::string::String>;
-
- #[inline]
- fn try_from(s: alloc::string::String) -> Result<Self, Self::Error> {
- match <&$slice<S>>::try_from(s.as_str()) {
- Ok(_) => {
- // This is safe because `<&$slice<S>>::try_from(s)?` ensures
- // that the string `s` is valid.
- Ok(Self {
- _spec: core::marker::PhantomData,
- inner: s,
- })
- }
- Err(e) => Err(crate::types::CreationError::new(e, s)),
- }
- }
- }
-
- impl<S: crate::spec::Spec> alloc::str::FromStr for $ty<S> {
- type Err = crate::validate::Error;
-
- #[inline]
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- core::convert::TryFrom::try_from(s)
- }
- }
-
- impl<S: crate::spec::Spec> core::ops::Deref for $ty<S> {
- type Target = $slice<S>;
-
- #[inline]
- fn deref(&self) -> &$slice<S> {
- self.as_ref()
- }
- }
-
- impl_cmp!(str, $slice<S>, alloc::borrow::Cow<'_, str>);
- impl_cmp!(str, &$slice<S>, alloc::borrow::Cow<'_, str>);
- impl_cmp2_as_str!(&$slice<S>, alloc::borrow::Cow<'_, $slice<T>>);
-
- impl_cmp!(str, str, $ty<S>);
- impl_cmp!(str, &str, $ty<S>);
- impl_cmp!(str, alloc::borrow::Cow<'_, str>, $ty<S>);
- impl_cmp!(str, alloc::string::String, $ty<S>);
- impl_cmp2!(str, $slice<S>, $ty<T>);
- impl_cmp2!(str, &$slice<S>, $ty<T>);
- impl_cmp2_as_str!(alloc::borrow::Cow<'_, $slice<S>>, $ty<T>);
-
- impl<S: crate::spec::Spec> core::fmt::Display for $ty<S> {
- #[inline]
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.write_str(self.as_str())
- }
- }
-
- /// Serde deserializer implementation.
- #[cfg(all(feature = "alloc", feature = "serde"))]
- mod __serde_owned {
- use super::$ty;
-
- use core::{convert::TryFrom, fmt, marker::PhantomData};
-
- #[cfg(all(feature = "serde", feature = "alloc"))]
- use alloc::string::String;
-
- use serde::{
- de::{self, Visitor},
- Deserialize, Deserializer,
- };
-
- /// Custom owned string visitor.
- #[derive(Debug, Clone, Copy)]
- struct CustomStringVisitor<S>(PhantomData<fn() -> S>);
-
- impl<'de, S: crate::spec::Spec> Visitor<'de> for CustomStringVisitor<S> {
- type Value = $ty<S>;
-
- #[inline]
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str($expecting)
- }
-
- #[inline]
- fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- <$ty<S> as TryFrom<&str>>::try_from(v).map_err(E::custom)
- }
-
- #[cfg(all(feature = "serde", feature = "alloc"))]
- #[inline]
- fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- <$ty<S> as TryFrom<String>>::try_from(v).map_err(E::custom)
- }
- }
-
- impl<'de, S: crate::spec::Spec> Deserialize<'de> for $ty<S> {
- #[inline]
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- deserializer.deserialize_str(CustomStringVisitor::<S>(PhantomData))
- }
- }
- }
- };
-}
-
-/// Implements trivial conversions and other useful traits between two IRI types.
-///
-/// Implemented traits:
-///
-/// * type conversion
-/// + `AsRef<$to_slice> for $from_slice`
-/// + `AsRef<$to_slice> for $from_owned`
-/// + `From<$from_slice> for $to_slice`
-/// + `From<$from_owned> for $to_owned`
-/// + `TryFrom<&$to_slice> for &$from_slice`
-/// + `TryFrom<$to_owned> for $from_owned`
-/// * comparison (only `PartialEq` impls are listed, but `PartialOrd` is also implemented).
-/// + `$from_slice` and `$to_slice`
-/// - `PartialEq<$from_slice> for $to_slice`
-/// - `PartialEq<$to_slice> for $from_slice`
-/// - `PartialEq<&$from_slice> for $to_slice`
-/// - `PartialEq<$to_slice> for &$from_slice`
-/// - `PartialEq<$from_slice> for &$to_slice`
-/// - `PartialEq<&$to_slice> for $from_slice`
-/// - `PartialEq<$from_slice> for Cow<'_, $to_slice>`
-/// - `PartialEq<Cow<'_, $to_slice>> for $from_slice`
-/// - `PartialEq<&$from_slice> for Cow<'_, $to_slice>`
-/// - `PartialEq<Cow<'_, $to_slice>> for &$from_slice`
-/// - `PartialEq<Cow<'_, $from_slice>> for $to_slice`
-/// - `PartialEq<$to_slice> for Cow<'_, $from_slice>`
-/// - `PartialEq<Cow<'_, $from_slice>> for &$to_slice`
-/// - `PartialEq<&$to_slice> for Cow<'_, $from_slice>`
-/// + `$from_slice` and `$to_owned`
-/// - `PartialEq<$from_slice> for $to_owned`
-/// - `PartialEq<$to_owned> for $from_slice`
-/// - `PartialEq<&$from_slice> for $to_owned`
-/// - `PartialEq<$to_owned> for &$from_slice`
-/// - `PartialEq<Cow<'_, $from_slice>> for $to_owned`
-/// - `PartialEq<$to_owned> for Cow<'_, $from_slice>`
-/// + `$from_owned` and `$to_slice`
-/// - `PartialEq<$from_owned> for $to_slice`
-/// - `PartialEq<$to_slice> for $from_owned`
-/// - `PartialEq<$from_owned> for &$to_slice`
-/// - `PartialEq<&$to_slice> for $from_owned`
-/// - `PartialEq<$from_owned> for Cow<'_, $to_slice>`
-/// - `PartialEq<Cow<'_, $to_slice>> for $from_owned`
-/// + `$from_owned` and `$to_owned`
-/// - `PartialEq<$from_owned> for $to_owned`
-/// - `PartialEq<$to_owned> for $from_owned`
-macro_rules! impl_trivial_conv_between_iri {
- (
- from_slice: $from_slice:ident,
- from_owned: $from_owned:ident,
- to_slice: $to_slice:ident,
- to_owned: $to_owned:ident,
- ) => {
- impl<S: crate::spec::Spec> AsRef<$to_slice<S>> for $from_slice<S> {
- #[inline]
- fn as_ref(&self) -> &$to_slice<S> {
- // SAFETY: `$from_slice<S>` should be subset of `$to_slice<S>`.
- // The caller of `impl_trivial_conv_between_iri!` macro is
- // responsible for guaranteeing that.
- unsafe { <$to_slice<S>>::new_maybe_unchecked(self.as_str()) }
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<S: crate::spec::Spec> AsRef<$to_slice<S>> for $from_owned<S> {
- #[inline]
- fn as_ref(&self) -> &$to_slice<S> {
- AsRef::<$from_slice<S>>::as_ref(self).as_ref()
- }
- }
-
- impl<'a, S: crate::spec::Spec> From<&'a $from_slice<S>> for &'a $to_slice<S> {
- #[inline]
- fn from(s: &'a $from_slice<S>) -> &'a $to_slice<S> {
- s.as_ref()
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<S: crate::spec::Spec> From<$from_owned<S>> for $to_owned<S> {
- #[inline]
- fn from(s: $from_owned<S>) -> $to_owned<S> {
- // SAFETY: `$from_slice<S>` should be subset of `$to_slice<S>`.
- // The caller of `impl_trivial_conv_between_iri!` macro is
- // responsible for guaranteeing that.
- unsafe { <$to_owned<S>>::new_maybe_unchecked(s.into()) }
- }
- }
-
- impl<'a, S: crate::spec::Spec> core::convert::TryFrom<&'a $to_slice<S>>
- for &'a $from_slice<S>
- {
- type Error = crate::validate::Error;
-
- #[inline]
- fn try_from(s: &'a $to_slice<S>) -> Result<Self, Self::Error> {
- Self::try_from(s.as_str())
- }
- }
-
- #[cfg(feature = "alloc")]
- impl<S: crate::spec::Spec> core::convert::TryFrom<$to_owned<S>> for $from_owned<S> {
- type Error = crate::types::CreationError<$to_owned<S>>;
-
- fn try_from(s: $to_owned<S>) -> Result<Self, Self::Error> {
- match <&$from_slice<S>>::try_from(s.as_str()) {
- // SAFETY: just checked `s.as_str()` is valid as `$from_slice<S>`, and it
- // requires the same syntax as `$from_owned<S>`.
- Ok(_) => Ok(unsafe { <$from_owned<S>>::new_always_unchecked(s.into()) }),
- Err(e) => Err(crate::types::CreationError::new(e, s)),
- }
- }
- }
-
- impl_cmp2_as_str!($from_slice<S>, $to_slice<T>);
- impl_cmp2_as_str!(&$from_slice<S>, $to_slice<T>);
- impl_cmp2_as_str!($from_slice<S>, &$to_slice<T>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!($from_slice<S>, alloc::borrow::Cow<'_, $to_slice<T>>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!(&$from_slice<S>, alloc::borrow::Cow<'_, $to_slice<T>>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!(alloc::borrow::Cow<'_, $from_slice<S>>, $to_slice<T>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!(alloc::borrow::Cow<'_, $from_slice<S>>, &$to_slice<T>);
-
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!($from_slice<S>, $to_owned<T>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!(&$from_slice<S>, $to_owned<T>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!(alloc::borrow::Cow<'_, $from_slice<S>>, $to_owned<T>);
-
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!($from_owned<S>, $to_slice<T>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!($from_owned<S>, &$to_slice<T>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!($from_owned<S>, alloc::borrow::Cow<'_, $to_slice<T>>);
- #[cfg(feature = "alloc")]
- impl_cmp2_as_str!($from_owned<S>, $to_owned<T>);
- };
-}
diff --git a/vendor/iri-string/src/types/generic/normal.rs b/vendor/iri-string/src/types/generic/normal.rs
deleted file mode 100644
index 641a022b..00000000
--- a/vendor/iri-string/src/types/generic/normal.rs
+++ /dev/null
@@ -1,944 +0,0 @@
-//! Usual absolute IRI (fragment part being allowed).
-
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-
-use crate::components::AuthorityComponents;
-#[cfg(feature = "alloc")]
-use crate::mask_password::password_range_to_hide;
-use crate::mask_password::PasswordMasked;
-use crate::normalize::{Error, NormalizationInput, Normalized, NormalizednessCheckMode};
-use crate::parser::trusted as trusted_parser;
-#[cfg(feature = "alloc")]
-use crate::raw;
-use crate::spec::Spec;
-use crate::types::{RiAbsoluteStr, RiFragmentStr, RiQueryStr, RiReferenceStr};
-#[cfg(feature = "alloc")]
-use crate::types::{RiAbsoluteString, RiFragmentString, RiReferenceString};
-use crate::validate::iri;
-
-define_custom_string_slice! {
- /// A borrowed string of an absolute IRI possibly with fragment part.
- ///
- /// This corresponds to [`IRI` rule] in [RFC 3987] (and [`URI` rule] in [RFC 3986]).
- /// The rule for `IRI` is `scheme ":" ihier-part [ "?" iquery ] [ "#" ifragment ]`.
- /// In other words, this is [`RiAbsoluteStr`] with fragment part allowed.
- ///
- /// # Valid values
- ///
- /// This type can have an IRI (which is absolute, and may have fragment part).
- ///
- /// ```
- /// # use iri_string::types::IriStr;
- /// assert!(IriStr::new("https://user:pass@example.com:8080").is_ok());
- /// assert!(IriStr::new("https://example.com/").is_ok());
- /// assert!(IriStr::new("https://example.com/foo?bar=baz").is_ok());
- /// assert!(IriStr::new("https://example.com/foo?bar=baz#qux").is_ok());
- /// assert!(IriStr::new("foo:bar").is_ok());
- /// assert!(IriStr::new("foo:").is_ok());
- /// // `foo://.../` below are all allowed. See the crate documentation for detail.
- /// assert!(IriStr::new("foo:/").is_ok());
- /// assert!(IriStr::new("foo://").is_ok());
- /// assert!(IriStr::new("foo:///").is_ok());
- /// assert!(IriStr::new("foo:////").is_ok());
- /// assert!(IriStr::new("foo://///").is_ok());
- /// ```
- ///
- /// Relative IRI reference is not allowed.
- ///
- /// ```
- /// # use iri_string::types::IriStr;
- /// // This is relative path.
- /// assert!(IriStr::new("foo/bar").is_err());
- /// // `/foo/bar` is an absolute path, but it is authority-relative.
- /// assert!(IriStr::new("/foo/bar").is_err());
- /// // `//foo/bar` is termed "network-path reference",
- /// // or usually called "protocol-relative reference".
- /// assert!(IriStr::new("//foo/bar").is_err());
- /// // Same-document reference is relative.
- /// assert!(IriStr::new("#foo").is_err());
- /// // Empty string is not a valid absolute IRI.
- /// assert!(IriStr::new("").is_err());
- /// ```
- ///
- /// Some characters and sequences cannot used in an IRI.
- ///
- /// ```
- /// # use iri_string::types::IriStr;
- /// // `<` and `>` cannot directly appear in an IRI.
- /// assert!(IriStr::new("<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in an IRI.
- /// assert!(IriStr::new("%").is_err());
- /// assert!(IriStr::new("%GG").is_err());
- /// ```
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`IRI` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`URI` rule]: https://tools.ietf.org/html/rfc3986#section-3
- /// [`RiAbsoluteStr`]: struct.RiAbsoluteStr.html
- struct RiStr {
- validator = iri,
- expecting_msg = "IRI string",
- }
-}
-
-#[cfg(feature = "alloc")]
-define_custom_string_owned! {
- /// An owned string of an absolute IRI possibly with fragment part.
- ///
- /// This corresponds to [`IRI` rule] in [RFC 3987] (and [`URI` rule] in [RFC 3986]).
- /// The rule for `IRI` is `scheme ":" ihier-part [ "?" iquery ] [ "#" ifragment ]`.
- /// In other words, this is [`RiAbsoluteString`] with fragment part allowed.
- ///
- /// For details, see the document for [`RiStr`].
- ///
- /// Enabled by `alloc` or `std` feature.
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`IRI` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`URI` rule]: https://tools.ietf.org/html/rfc3986#section-3
- /// [`RiAbsoluteString`]: struct.RiAbsoluteString.html
- struct RiString {
- validator = iri,
- slice = RiStr,
- expecting_msg = "IRI string",
- }
-}
-
-impl<S: Spec> RiStr<S> {
- /// Splits the IRI into an absolute IRI part and a fragment part.
- ///
- /// A leading `#` character is truncated if the fragment part exists.
- ///
- /// # Examples
- ///
- /// If the IRI has a fragment part, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriStr}, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux#corge")?;
- /// let (absolute, fragment) = iri.to_absolute_and_fragment();
- /// let fragment_expected = IriFragmentStr::new("corge")?;
- /// assert_eq!(absolute, "foo://bar/baz?qux=quux");
- /// assert_eq!(fragment, Some(fragment_expected));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// When the fragment part exists but is empty string, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriStr}, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux#")?;
- /// let (absolute, fragment) = iri.to_absolute_and_fragment();
- /// let fragment_expected = IriFragmentStr::new("")?;
- /// assert_eq!(absolute, "foo://bar/baz?qux=quux");
- /// assert_eq!(fragment, Some(fragment_expected));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the IRI has no fragment, `None` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriStr, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux")?;
- /// let (absolute, fragment) = iri.to_absolute_and_fragment();
- /// assert_eq!(absolute, "foo://bar/baz?qux=quux");
- /// assert_eq!(fragment, None);
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- pub fn to_absolute_and_fragment(&self) -> (&RiAbsoluteStr<S>, Option<&RiFragmentStr<S>>) {
- let (prefix, fragment) = trusted_parser::split_fragment(self.as_str());
- // SAFETY: an IRI without fragment part is also an absolute IRI.
- let prefix = unsafe { RiAbsoluteStr::new_maybe_unchecked(prefix) };
- let fragment = fragment.map(|fragment| {
- // SAFETY: `trusted_parser::split_fragment()` must return a valid fragment component.
- unsafe { RiFragmentStr::new_maybe_unchecked(fragment) }
- });
-
- (prefix, fragment)
- }
-
- /// Strips the fragment part if exists, and returns [`&RiAbsoluteStr`][`RiAbsoluteStr`].
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriStr, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux#corge")?;
- /// assert_eq!(iri.to_absolute(), "foo://bar/baz?qux=quux");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriStr, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux")?;
- /// assert_eq!(iri.to_absolute(), "foo://bar/baz?qux=quux");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// [`RiAbsoluteStr`]: struct.RiAbsoluteStr.html
- #[must_use]
- pub fn to_absolute(&self) -> &RiAbsoluteStr<S> {
- let prefix_len = trusted_parser::split_fragment(self.as_str()).0.len();
- // SAFETY: IRI without the fragment part (including a leading `#` character)
- // is also an absolute IRI.
- unsafe { RiAbsoluteStr::new_maybe_unchecked(&self.as_str()[..prefix_len]) }
- }
-
- /// Returns Ok`(())` if the IRI is normalizable by the RFC 3986 algorithm.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("HTTP://example.COM/foo/%2e/bar/..")?;
- /// assert!(iri.ensure_rfc3986_normalizable().is_ok());
- ///
- /// let iri2 = IriStr::new("scheme:/..//bar")?;
- /// // The normalization result would be `scheme://bar` according to RFC
- /// // 3986, but it is unintended and should be treated as a failure.
- /// // This crate automatically handles this case so that `.normalize()` won't fail.
- /// assert!(!iri.ensure_rfc3986_normalizable().is_err());
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn ensure_rfc3986_normalizable(&self) -> Result<(), Error> {
- NormalizationInput::from(self).ensure_rfc3986_normalizable()
- }
-
- /// Returns `true` if the IRI is already normalized.
- ///
- /// This returns the same result as `self.normalize().to_string() == self`,
- /// but does this more efficiently without heap allocation.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query#fragment")?;
- /// assert!(!iri.is_normalized());
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query#fragment");
- /// assert!(normalized.is_normalized());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("scheme:/.///foo")?;
- /// // Already normalized.
- /// assert!(iri.is_normalized());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("scheme:relative/..//not-a-host")?;
- /// // Default normalization algorithm assumes the path part to be NOT opaque.
- /// assert!(!iri.is_normalized());
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "scheme:/.//not-a-host");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- #[inline]
- pub fn is_normalized(&self) -> bool {
- trusted_parser::is_normalized::<S>(self.as_str(), NormalizednessCheckMode::Default)
- }
-
- /// Returns `true` if the IRI is already normalized in the sense of RFC 3986.
- ///
- /// This returns the same result as
- /// `self.ensure_rfc3986_normalizable() && (self.normalize().to_string() == self)`,
- /// but does this more efficiently without heap allocation.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query#fragment")?;
- /// assert!(!iri.is_normalized_rfc3986());
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query#fragment");
- /// assert!(normalized.is_normalized_rfc3986());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("scheme:/.///foo")?;
- /// // Not normalized in the sense of RFC 3986.
- /// assert!(!iri.is_normalized_rfc3986());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("scheme:relative/..//not-a-host")?;
- /// // RFC 3986 normalization algorithm assumes the path part to be NOT opaque.
- /// assert!(!iri.is_normalized_rfc3986());
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "scheme:/.//not-a-host");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- #[inline]
- pub fn is_normalized_rfc3986(&self) -> bool {
- trusted_parser::is_normalized::<S>(self.as_str(), NormalizednessCheckMode::Rfc3986)
- }
-
- /// Returns `true` if the IRI is already normalized in the sense of
- /// [`normalize_but_preserve_authorityless_relative_path`] method.
- ///
- /// This returns the same result as
- /// `self.normalize_but_preserve_authorityless_relative_path().to_string() == self`,
- /// but does this more efficiently without heap allocation.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query#fragment")?;
- /// assert!(!iri.is_normalized_but_authorityless_relative_path_preserved());
- ///
- /// let normalized = iri
- /// .normalize_but_preserve_authorityless_relative_path()
- /// .to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query#fragment");
- /// assert!(normalized.is_normalized());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("scheme:/.///foo")?;
- /// // Already normalized in the sense of
- /// // `normalize_but_opaque_authorityless_relative_path()` method.
- /// assert!(iri.is_normalized_but_authorityless_relative_path_preserved());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("scheme:relative/..//not-a-host")?;
- /// // Relative path is treated as opaque since the autority component is absent.
- /// assert!(iri.is_normalized_but_authorityless_relative_path_preserved());
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// [`normalize_but_preserve_authorityless_relative_path`]:
- /// `Self::normalize_but_preserve_authorityless_relative_path`
- #[must_use]
- #[inline]
- pub fn is_normalized_but_authorityless_relative_path_preserved(&self) -> bool {
- trusted_parser::is_normalized::<S>(
- self.as_str(),
- NormalizednessCheckMode::PreserveAuthoritylessRelativePath,
- )
- }
-
- /// Returns the normalized IRI.
- ///
- /// # Notes
- ///
- /// For some abnormal IRIs, the normalization can produce semantically
- /// incorrect string that looks syntactically valid. To avoid security
- /// issues by this trap, the normalization algorithm by this crate
- /// automatically applies the workaround.
- ///
- /// If you worry about this, test by [`RiStr::ensure_rfc3986_normalizable`]
- /// method or [`Normalized::ensure_rfc3986_normalizable`] before using the
- /// result string.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query#fragment")?;
- ///
- /// let normalized = iri.normalize().to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query#fragment");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn normalize(&self) -> Normalized<'_, Self> {
- Normalized::from_input(NormalizationInput::from(self)).and_normalize()
- }
-
- /// Returns the normalized IRI, but preserving dot segments in relative path
- /// if the authority component is absent.
- ///
- /// This normalization would be similar to that of [WHATWG URL Standard]
- /// while this implementation is not guaranteed to stricly follow the spec.
- ///
- /// Note that this normalization algorithm is not compatible with RFC 3986
- /// algorithm for some inputs.
- ///
- /// Note that case normalization and percent-encoding normalization will
- /// still be applied to any path.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("HTTP://example.COM/foo/./bar/%2e%2e/../baz?query#fragment")?;
- ///
- /// let normalized = iri
- /// .normalize_but_preserve_authorityless_relative_path()
- /// .to_dedicated_string();
- /// assert_eq!(normalized, "http://example.com/baz?query#fragment");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("scheme:relative/../f%6f%6f")?;
- ///
- /// let normalized = iri
- /// .normalize_but_preserve_authorityless_relative_path()
- /// .to_dedicated_string();
- /// assert_eq!(normalized, "scheme:relative/../foo");
- /// // `.normalize()` would normalize this to `scheme:/foo`.
- /// # assert_eq!(iri.normalize().to_dedicated_string(), "scheme:/foo");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// [WHATWG URL Standard]: https://url.spec.whatwg.org/
- #[inline]
- #[must_use]
- pub fn normalize_but_preserve_authorityless_relative_path(&self) -> Normalized<'_, Self> {
- Normalized::from_input(NormalizationInput::from(self))
- .and_normalize_but_preserve_authorityless_relative_path()
- }
-
- /// Returns the proxy to the IRI with password masking feature.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("http://user:password@example.com/path?query")?;
- /// let masked = iri.mask_password();
- /// assert_eq!(masked.to_dedicated_string(), "http://user:@example.com/path?query");
- ///
- /// assert_eq!(
- /// masked.replace_password("${password}").to_string(),
- /// "http://user:${password}@example.com/path?query"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn mask_password(&self) -> PasswordMasked<'_, Self> {
- PasswordMasked::new(self)
- }
-}
-
-/// Components getters.
-impl<S: Spec> RiStr<S> {
- /// Returns the scheme.
- ///
- /// The following colon is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.scheme_str(), "http");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn scheme_str(&self) -> &str {
- trusted_parser::extract_scheme_absolute(self.as_str())
- }
-
- /// Returns the authority.
- ///
- /// The leading `//` is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.authority_str(), Some("example.com"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_str(&self) -> Option<&str> {
- trusted_parser::extract_authority_absolute(self.as_str())
- }
-
- /// Returns the path.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.path_str(), "/pathpath");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.path_str(), "uuid:10db315b-fcd1-4428-aca8-15babc9a2da2");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn path_str(&self) -> &str {
- trusted_parser::extract_path_absolute(self.as_str())
- }
-
- /// Returns the query.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::{IriQueryStr, IriStr};
- ///
- /// let iri = IriStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// let query = IriQueryStr::new("queryquery")?;
- /// assert_eq!(iri.query(), Some(query));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.query(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query(&self) -> Option<&RiQueryStr<S>> {
- AsRef::<RiReferenceStr<S>>::as_ref(self).query()
- }
-
- /// Returns the query in a raw string slice.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.query_str(), Some("queryquery"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.query_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query_str(&self) -> Option<&str> {
- trusted_parser::extract_query(self.as_str())
- }
-
- /// Returns the fragment part if exists.
- ///
- /// A leading `#` character is truncated if the fragment part exists.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriStr}, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux#corge")?;
- /// let fragment = IriFragmentStr::new("corge")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriStr}, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux#")?;
- /// let fragment = IriFragmentStr::new("")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriStr, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux")?;
- /// assert_eq!(iri.fragment(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn fragment(&self) -> Option<&RiFragmentStr<S>> {
- AsRef::<RiReferenceStr<S>>::as_ref(self).fragment()
- }
-
- /// Returns the fragment part as a raw string slice if exists.
- ///
- /// A leading `#` character is truncated if the fragment part exists.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriStr, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux#corge")?;
- /// assert_eq!(iri.fragment_str(), Some("corge"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriStr, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux#")?;
- /// assert_eq!(iri.fragment_str(), Some(""));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriStr, validate::Error};
- /// let iri = IriStr::new("foo://bar/baz?qux=quux")?;
- /// assert_eq!(iri.fragment_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn fragment_str(&self) -> Option<&str> {
- AsRef::<RiReferenceStr<S>>::as_ref(self).fragment_str()
- }
-
- /// Returns the authority components.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("http://user:pass@example.com:8080/pathpath?queryquery")?;
- /// let authority = iri.authority_components()
- /// .expect("authority is available");
- /// assert_eq!(authority.userinfo(), Some("user:pass"));
- /// assert_eq!(authority.host(), "example.com");
- /// assert_eq!(authority.port(), Some("8080"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriStr;
- ///
- /// let iri = IriStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_components(&self) -> Option<AuthorityComponents<'_>> {
- AuthorityComponents::from_iri(self.as_ref())
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> RiString<S> {
- /// Splits the IRI into an absolute IRI part and a fragment part.
- ///
- /// A leading `#` character is truncated if the fragment part exists.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::convert::TryFrom;
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentString, IriString}, validate::Error};
- /// let iri = "foo://bar/baz?qux=quux#corge".parse::<IriString>()?;
- /// let (absolute, fragment) = iri.into_absolute_and_fragment();
- /// let fragment_expected = IriFragmentString::try_from("corge".to_owned())
- /// .map_err(|e| e.validation_error())?;
- /// assert_eq!(absolute, "foo://bar/baz?qux=quux");
- /// assert_eq!(fragment, Some(fragment_expected));
- /// # Ok::<_, Error>(())
- ///
- /// ```
- ///
- /// ```
- /// use std::convert::TryFrom;
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentString, IriString}, validate::Error};
- /// let iri = "foo://bar/baz?qux=quux#".parse::<IriString>()?;
- /// let (absolute, fragment) = iri.into_absolute_and_fragment();
- /// let fragment_expected = IriFragmentString::try_from("".to_owned())
- /// .map_err(|e| e.validation_error())?;
- /// assert_eq!(absolute, "foo://bar/baz?qux=quux");
- /// assert_eq!(fragment, Some(fragment_expected));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// use std::convert::TryFrom;
- /// # use iri_string::{spec::IriSpec, types::IriString, validate::Error};
- /// let iri = "foo://bar/baz?qux=quux".parse::<IriString>()?;
- /// let (absolute, fragment) = iri.into_absolute_and_fragment();
- /// assert_eq!(absolute, "foo://bar/baz?qux=quux");
- /// assert_eq!(fragment, None);
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- pub fn into_absolute_and_fragment(self) -> (RiAbsoluteString<S>, Option<RiFragmentString<S>>) {
- let (prefix, fragment) = raw::split_fragment_owned(self.into());
- // SAFETY: an IRI without fragment part is also an absolute IRI.
- let prefix = unsafe { RiAbsoluteString::new_maybe_unchecked(prefix) };
- let fragment = fragment.map(|fragment| {
- // SAFETY: the string returned by `raw::split_fragment_owned()` must
- // be the fragment part, and must also be a substring of the source IRI.
- unsafe { RiFragmentString::new_maybe_unchecked(fragment) }
- });
-
- (prefix, fragment)
- }
-
- /// Strips the fragment part if exists, and returns an [`RiAbsoluteString`].
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriString, validate::Error};
- /// let iri = "foo://bar/baz?qux=quux#corge".parse::<IriString>()?;
- /// assert_eq!(iri.into_absolute(), "foo://bar/baz?qux=quux");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriString, validate::Error};
- /// let iri = "foo://bar/baz?qux=quux".parse::<IriString>()?;
- /// assert_eq!(iri.into_absolute(), "foo://bar/baz?qux=quux");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// [`RiAbsoluteString`]: struct.RiAbsoluteString.html
- #[must_use]
- pub fn into_absolute(self) -> RiAbsoluteString<S> {
- let mut s: String = self.into();
- raw::remove_fragment(&mut s);
- // SAFETY: an IRI without fragment part is also an absolute IRI.
- unsafe { RiAbsoluteString::new_maybe_unchecked(s) }
- }
-
- /// Sets the fragment part to the given string.
- ///
- /// Removes fragment part (and following `#` character) if `None` is given.
- pub fn set_fragment(&mut self, fragment: Option<&RiFragmentStr<S>>) {
- raw::set_fragment(&mut self.inner, fragment.map(AsRef::as_ref));
- debug_assert!(iri::<S>(&self.inner).is_ok());
- }
-
- /// Removes the password completely (including separator colon) from `self` even if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriString;
- ///
- /// let mut iri = IriString::try_from("http://user:password@example.com/path?query")?;
- /// iri.remove_password_inline();
- /// assert_eq!(iri, "http://user@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// Even if the password is empty, the password and separator will be removed.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriString;
- ///
- /// let mut iri = IriString::try_from("http://user:@example.com/path?query")?;
- /// iri.remove_password_inline();
- /// assert_eq!(iri, "http://user@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn remove_password_inline(&mut self) {
- let pw_range = match password_range_to_hide(self.as_slice().as_ref()) {
- Some(v) => v,
- None => return,
- };
- let separator_colon = pw_range.start - 1;
- // SAFETY: the IRI must still be valid after the password component and
- // the leading separator colon is removed.
- unsafe {
- let buf = self.as_inner_mut();
- buf.drain(separator_colon..pw_range.end);
- debug_assert!(
- RiStr::<S>::new(buf).is_ok(),
- "[validity] the IRI must be valid after the password component is removed"
- );
- }
- }
-
- /// Replaces the non-empty password in `self` to the empty password.
- ///
- /// This leaves the separator colon if the password part was available.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriString;
- ///
- /// let mut iri = IriString::try_from("http://user:password@example.com/path?query")?;
- /// iri.remove_nonempty_password_inline();
- /// assert_eq!(iri, "http://user:@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the password is empty, it is left as is.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriString;
- ///
- /// let mut iri = IriString::try_from("http://user:@example.com/path?query")?;
- /// iri.remove_nonempty_password_inline();
- /// assert_eq!(iri, "http://user:@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn remove_nonempty_password_inline(&mut self) {
- let pw_range = match password_range_to_hide(self.as_slice().as_ref()) {
- Some(v) if !v.is_empty() => v,
- _ => return,
- };
- debug_assert_eq!(
- self.as_str().as_bytes().get(pw_range.start - 1).copied(),
- Some(b':'),
- "[validity] the password component must be prefixed with a separator colon"
- );
- // SAFETY: the IRI must still be valid if the password is replaced with
- // empty string.
- unsafe {
- let buf = self.as_inner_mut();
- buf.drain(pw_range);
- debug_assert!(
- RiStr::<S>::new(buf).is_ok(),
- "[validity] the IRI must be valid after the password component is removed"
- );
- }
- }
-}
-
-impl_trivial_conv_between_iri! {
- from_slice: RiStr,
- from_owned: RiString,
- to_slice: RiReferenceStr,
- to_owned: RiReferenceString,
-}
diff --git a/vendor/iri-string/src/types/generic/query.rs b/vendor/iri-string/src/types/generic/query.rs
deleted file mode 100644
index 40057f23..00000000
--- a/vendor/iri-string/src/types/generic/query.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-//! Query string.
-
-use crate::{
- spec::Spec,
- validate::{query, Error},
-};
-
-define_custom_string_slice! {
- /// A borrowed slice of an IRI query (i.e. after the first `?` and before the first `#`).
- ///
- /// This corresponds to [`iquery` rule] in [RFC 3987] (and [`query` rule] in [RFC 3986]).
- /// The rule for `ifragment` is `*( ipchar / iprivate / "/" / "?" )`.
- ///
- /// # Valid values
- ///
- /// This type can have an IRI fragment.
- /// Note that the IRI `foo://bar/baz#qux` has the fragment `qux`, **not** `#qux`.
- ///
- /// ```
- /// # use iri_string::types::IriFragmentStr;
- /// assert!(IriFragmentStr::new("").is_ok());
- /// assert!(IriFragmentStr::new("foo").is_ok());
- /// assert!(IriFragmentStr::new("foo/bar").is_ok());
- /// assert!(IriFragmentStr::new("/foo/bar").is_ok());
- /// assert!(IriFragmentStr::new("//foo/bar").is_ok());
- /// assert!(IriFragmentStr::new("https://user:pass@example.com:8080").is_ok());
- /// assert!(IriFragmentStr::new("https://example.com/").is_ok());
- /// ```
- ///
- /// Some characters and sequences cannot used in a fragment.
- ///
- /// ```
- /// # use iri_string::types::IriFragmentStr;
- /// // `<` and `>` cannot directly appear in an IRI reference.
- /// assert!(IriFragmentStr::new("<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in an IRI reference.
- /// assert!(IriFragmentStr::new("%").is_err());
- /// assert!(IriFragmentStr::new("%GG").is_err());
- /// // Hash sign `#` cannot appear in an IRI fragment.
- /// assert!(IriFragmentStr::new("#hash").is_err());
- /// ```
- /// ```
- /// use iri_string::types::IriQueryStr;
- /// assert!(IriQueryStr::new("").is_ok());
- /// assert!(IriQueryStr::new("foo").is_ok());
- /// assert!(IriQueryStr::new("foo/bar").is_ok());
- /// assert!(IriQueryStr::new("/foo/bar").is_ok());
- /// assert!(IriQueryStr::new("//foo/bar").is_ok());
- /// assert!(IriQueryStr::new("https://user:pass@example.com:8080").is_ok());
- /// assert!(IriQueryStr::new("https://example.com/").is_ok());
- /// // Question sign `?` can appear in an IRI query.
- /// assert!(IriQueryStr::new("query?again").is_ok());
- /// ```
- ///
- /// Some characters and sequences cannot used in a query.
- ///
- /// ```
- /// use iri_string::types::IriQueryStr;
- /// // `<` and `>` cannot directly appear in an IRI reference.
- /// assert!(IriQueryStr::new("<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in an IRI reference.
- /// assert!(IriQueryStr::new("%").is_err());
- /// assert!(IriQueryStr::new("%GG").is_err());
- /// // Hash sign `#` cannot appear in an IRI query.
- /// assert!(IriQueryStr::new("#hash").is_err());
- /// ```
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`query` rule]: https://tools.ietf.org/html/rfc3986#section-3.4
- /// [`iquery` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- struct RiQueryStr {
- validator = query,
- expecting_msg = "IRI query string",
- }
-}
-
-#[cfg(feature = "alloc")]
-define_custom_string_owned! {
- /// An owned string of an IRI fragment (i.e. after the first `#` character).
- ///
- /// This corresponds to [`iquery` rule] in [RFC 3987] (and [`query` rule] in [RFC 3986]).
- /// The rule for `absolute-IRI` is `*( ipchar / iprivate / "/" / "?" )`.
- ///
- /// For details, see the documentation for [`RiQueryStr`].
- ///
- /// Enabled by `alloc` or `std` feature.
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`query` rule]: https://tools.ietf.org/html/rfc3986#section-3.4
- /// [`iquery` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`RiQueryStr`]: struct.RiQueryStr.html
- struct RiQueryString {
- validator = query,
- slice = RiQueryStr,
- expecting_msg = "IRI query string",
- }
-}
-
-impl<S: Spec> RiQueryStr<S> {
- /// Creates a new `&RiQueryStr` from the query part prefixed by `?`.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::types::IriQueryStr;
- /// assert!(IriQueryStr::from_prefixed("?").is_ok());
- /// assert!(IriQueryStr::from_prefixed("?foo").is_ok());
- /// assert!(IriQueryStr::from_prefixed("?foo/bar").is_ok());
- /// assert!(IriQueryStr::from_prefixed("?/foo/bar").is_ok());
- /// assert!(IriQueryStr::from_prefixed("?//foo/bar").is_ok());
- /// assert!(IriQueryStr::from_prefixed("?https://user:pass@example.com:8080").is_ok());
- /// assert!(IriQueryStr::from_prefixed("?https://example.com/").is_ok());
- /// // Question sign `?` can appear in an IRI query.
- /// assert!(IriQueryStr::from_prefixed("?query?again").is_ok());
- ///
- /// // `<` and `>` cannot directly appear in an IRI.
- /// assert!(IriQueryStr::from_prefixed("?<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in an IRI.
- /// assert!(IriQueryStr::new("?%").is_err());
- /// assert!(IriQueryStr::new("?%GG").is_err());
- /// // `?` prefix is expected.
- /// assert!(IriQueryStr::from_prefixed("").is_err());
- /// assert!(IriQueryStr::from_prefixed("foo").is_err());
- /// // Hash sign `#` cannot appear in an IRI query.
- /// assert!(IriQueryStr::from_prefixed("?#hash").is_err());
- /// ```
- pub fn from_prefixed(s: &str) -> Result<&Self, Error> {
- if !s.starts_with('?') {
- return Err(Error::new());
- }
- TryFrom::try_from(&s[1..])
- }
-}
diff --git a/vendor/iri-string/src/types/generic/reference.rs b/vendor/iri-string/src/types/generic/reference.rs
deleted file mode 100644
index 9ac62281..00000000
--- a/vendor/iri-string/src/types/generic/reference.rs
+++ /dev/null
@@ -1,697 +0,0 @@
-//! IRI reference.
-
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-
-use crate::components::AuthorityComponents;
-#[cfg(feature = "alloc")]
-use crate::mask_password::password_range_to_hide;
-use crate::mask_password::PasswordMasked;
-use crate::normalize::Normalized;
-use crate::parser::trusted as trusted_parser;
-#[cfg(feature = "alloc")]
-use crate::raw;
-use crate::resolve::FixedBaseResolver;
-use crate::spec::Spec;
-use crate::types::{RiAbsoluteStr, RiFragmentStr, RiQueryStr, RiRelativeStr, RiStr};
-#[cfg(feature = "alloc")]
-use crate::types::{RiRelativeString, RiString};
-#[cfg(feature = "alloc")]
-use crate::validate::iri;
-use crate::validate::iri_reference;
-
-define_custom_string_slice! {
- /// A borrowed string of an absolute IRI possibly with fragment part.
- ///
- /// This corresponds to [`IRI-reference` rule] in [RFC 3987]
- /// (and [`URI-reference` rule] in [RFC 3986]).
- /// The rule for `IRI-reference` is `IRI / irelative-ref`.
- /// In other words, this is union of [`RiStr`] and [`RiRelativeStr`].
- ///
- /// # Valid values
- ///
- /// This type can have an IRI reference (which can be absolute or relative).
- ///
- /// ```
- /// # use iri_string::types::IriReferenceStr;
- /// assert!(IriReferenceStr::new("https://user:pass@example.com:8080").is_ok());
- /// assert!(IriReferenceStr::new("https://example.com/").is_ok());
- /// assert!(IriReferenceStr::new("https://example.com/foo?bar=baz").is_ok());
- /// assert!(IriReferenceStr::new("https://example.com/foo?bar=baz#qux").is_ok());
- /// assert!(IriReferenceStr::new("foo:bar").is_ok());
- /// assert!(IriReferenceStr::new("foo:").is_ok());
- /// // `foo://.../` below are all allowed. See the crate documentation for detail.
- /// assert!(IriReferenceStr::new("foo:/").is_ok());
- /// assert!(IriReferenceStr::new("foo://").is_ok());
- /// assert!(IriReferenceStr::new("foo:///").is_ok());
- /// assert!(IriReferenceStr::new("foo:////").is_ok());
- /// assert!(IriReferenceStr::new("foo://///").is_ok());
- /// assert!(IriReferenceStr::new("foo/bar").is_ok());
- /// assert!(IriReferenceStr::new("/foo/bar").is_ok());
- /// assert!(IriReferenceStr::new("//foo/bar").is_ok());
- /// assert!(IriReferenceStr::new("#foo").is_ok());
- /// ```
- ///
- /// Some characters and sequences cannot used in an IRI reference.
- ///
- /// ```
- /// # use iri_string::types::IriReferenceStr;
- /// // `<` and `>` cannot directly appear in an IRI reference.
- /// assert!(IriReferenceStr::new("<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in an IRI reference.
- /// assert!(IriReferenceStr::new("%").is_err());
- /// assert!(IriReferenceStr::new("%GG").is_err());
- /// ```
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`IRI-reference` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`URI-reference` rule]: https://tools.ietf.org/html/rfc3986#section-4.1
- /// [`RiRelativeStr`]: struct.RiRelativeStr.html
- /// [`RiStr`]: struct.RiStr.html
- struct RiReferenceStr {
- validator = iri_reference,
- expecting_msg = "IRI reference string",
- }
-}
-
-#[cfg(feature = "alloc")]
-define_custom_string_owned! {
- /// An owned string of an absolute IRI possibly with fragment part.
- ///
- /// This corresponds to [`IRI-reference` rule] in [RFC 3987]
- /// (and [`URI-reference` rule] in [RFC 3986]).
- /// The rule for `IRI-reference` is `IRI / irelative-ref`.
- /// In other words, this is union of [`RiString`] and [`RiRelativeString`].
- ///
- /// For details, see the document for [`RiReferenceStr`].
- ///
- /// Enabled by `alloc` or `std` feature.
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`IRI-reference` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`URI-reference` rule]: https://tools.ietf.org/html/rfc3986#section-4.1
- /// [`RiReferenceStr`]: struct.RiReferenceString.html
- /// [`RiRelativeString`]: struct.RiRelativeString.html
- /// [`RiString`]: struct.RiString.html
- struct RiReferenceString {
- validator = iri_reference,
- slice = RiReferenceStr,
- expecting_msg = "IRI reference string",
- }
-}
-
-impl<S: Spec> RiReferenceStr<S> {
- /// Returns the string as [`&RiStr`][`RiStr`], if it is valid as an IRI.
- ///
- /// If it is not an IRI, then [`&RiRelativeStr`][`RiRelativeStr`] is returned as `Err(_)`.
- ///
- /// [`RiRelativeStr`]: struct.RiRelativeStr.html
- /// [`RiStr`]: struct.RiStr.html
- pub fn to_iri(&self) -> Result<&RiStr<S>, &RiRelativeStr<S>> {
- // Check with `IRI` rule first, because the syntax rule for `IRI-reference` is
- // `IRI / irelative-ref`.
- //
- // > Some productions are ambiguous. The "first-match-wins" (a.k.a.
- // > "greedy") algorithm applies. For details, see [RFC3986].
- // >
- // > --- <https://tools.ietf.org/html/rfc3987#section-2.2>.
-
- <&RiStr<S>>::try_from(self.as_str()).map_err(|_| {
- // SAFETY: if an IRI reference is not an IRI, then it is a relative IRI.
- // See the RFC 3987 syntax rule `IRI-reference = IRI / irelative-ref`.
- unsafe { RiRelativeStr::new_maybe_unchecked(self.as_str()) }
- })
- }
-
- /// Returns the string as [`&RiRelativeStr`][`RiRelativeStr`], if it is valid as an IRI.
- ///
- /// If it is not an IRI, then [`&RiStr`][`RiStr`] is returned as `Err(_)`.
- ///
- /// [`RiRelativeStr`]: struct.RiRelativeStr.html
- /// [`RiStr`]: struct.RiStr.html
- pub fn to_relative_iri(&self) -> Result<&RiRelativeStr<S>, &RiStr<S>> {
- match self.to_iri() {
- Ok(iri) => Err(iri),
- Err(relative) => Ok(relative),
- }
- }
-
- /// Returns resolved IRI against the given base IRI.
- ///
- /// For IRI reference resolution output examples, see [RFC 3986 section 5.4].
- ///
- /// If you are going to resolve multiple references against the common base,
- /// consider using [`FixedBaseResolver`].
- ///
- /// # Strictness
- ///
- /// The IRI parsers provided by this crate is strict (e.g. `http:g` is
- /// always interpreted as a composition of the scheme `http` and the path
- /// `g`), so backward compatible parsing and resolution are not provided.
- /// About parser and resolver strictness, see [RFC 3986 section 5.4.2]:
- ///
- /// > Some parsers allow the scheme name to be present in a relative
- /// > reference if it is the same as the base URI scheme. This is considered
- /// > to be a loophole in prior specifications of partial URI
- /// > [RFC1630](https://tools.ietf.org/html/rfc1630). Its use should be
- /// > avoided but is allowed for backward compatibility.
- /// >
- /// > --- <https://tools.ietf.org/html/rfc3986#section-5.4.2>
- ///
- /// # Failures
- ///
- /// This method itself does not fail, but IRI resolution without WHATWG URL
- /// Standard serialization can fail in some minor cases.
- ///
- /// To see examples of such unresolvable IRIs, visit the documentation
- /// for [`normalize`][`crate::normalize`] module.
- ///
- /// [RFC 3986 section 5.4]: https://tools.ietf.org/html/rfc3986#section-5.4
- /// [RFC 3986 section 5.4.2]: https://tools.ietf.org/html/rfc3986#section-5.4.2
- pub fn resolve_against<'a>(&'a self, base: &'a RiAbsoluteStr<S>) -> Normalized<'a, RiStr<S>> {
- FixedBaseResolver::new(base).resolve(self.as_ref())
- }
-
- /// Returns the proxy to the IRI with password masking feature.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("http://user:password@example.com/path?query")?;
- /// let masked = iri.mask_password();
- /// assert_eq!(masked.to_dedicated_string(), "http://user:@example.com/path?query");
- ///
- /// assert_eq!(
- /// masked.replace_password("${password}").to_string(),
- /// "http://user:${password}@example.com/path?query"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn mask_password(&self) -> PasswordMasked<'_, Self> {
- PasswordMasked::new(self)
- }
-}
-
-/// Components getters.
-impl<S: Spec> RiReferenceStr<S> {
- /// Returns the scheme.
- ///
- /// The following colon is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.scheme_str(), Some("http"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("foo/bar:baz")?;
- /// assert_eq!(iri.scheme_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn scheme_str(&self) -> Option<&str> {
- trusted_parser::extract_scheme(self.as_str())
- }
-
- /// Returns the authority.
- ///
- /// The leading `//` is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.authority_str(), Some("example.com"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("foo/bar:baz")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_str(&self) -> Option<&str> {
- trusted_parser::extract_authority(self.as_str())
- }
-
- /// Returns the path.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.path_str(), "/pathpath");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.path_str(), "uuid:10db315b-fcd1-4428-aca8-15babc9a2da2");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("foo/bar:baz")?;
- /// assert_eq!(iri.path_str(), "foo/bar:baz");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn path_str(&self) -> &str {
- trusted_parser::extract_path(self.as_str())
- }
-
- /// Returns the query.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::{IriQueryStr, IriReferenceStr};
- ///
- /// let iri = IriReferenceStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// let query = IriQueryStr::new("queryquery")?;
- /// assert_eq!(iri.query(), Some(query));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.query(), None);
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::{IriQueryStr, IriReferenceStr};
- ///
- /// let iri = IriReferenceStr::new("foo/bar:baz?")?;
- /// let query = IriQueryStr::new("")?;
- /// assert_eq!(iri.query(), Some(query));
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query(&self) -> Option<&RiQueryStr<S>> {
- trusted_parser::extract_query(self.as_str()).map(|query| {
- // SAFETY: `extract_query` returns the query part of an IRI, and the
- // returned string should have only valid characters since is the
- // substring of the source IRI.
- unsafe { RiQueryStr::new_maybe_unchecked(query) }
- })
- }
-
- /// Returns the query as a raw string slice.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("http://example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.query_str(), Some("queryquery"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("urn:uuid:10db315b-fcd1-4428-aca8-15babc9a2da2")?;
- /// assert_eq!(iri.query_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("foo/bar:baz?")?;
- /// assert_eq!(iri.query_str(), Some(""));
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query_str(&self) -> Option<&str> {
- trusted_parser::extract_query(self.as_str())
- }
-
- /// Returns the fragment part if exists.
- ///
- /// A leading `#` character is truncated if the fragment part exists.
- ///
- /// # Examples
- ///
- /// If the IRI has a fragment part, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriReferenceStr}, validate::Error};
- /// let iri = IriReferenceStr::new("foo://bar/baz?qux=quux#corge")?;
- /// let fragment = IriFragmentStr::new("corge")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriReferenceStr}, validate::Error};
- /// let iri = IriReferenceStr::new("#foo")?;
- /// let fragment = IriFragmentStr::new("foo")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// When the fragment part exists but is empty string, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriReferenceStr}, validate::Error};
- /// let iri = IriReferenceStr::new("foo://bar/baz?qux=quux#")?;
- /// let fragment = IriFragmentStr::new("")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriReferenceStr}, validate::Error};
- /// let iri = IriReferenceStr::new("#")?;
- /// let fragment = IriFragmentStr::new("")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the IRI has no fragment, `None` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriReferenceStr, validate::Error};
- /// let iri = IriReferenceStr::new("foo://bar/baz?qux=quux")?;
- /// assert_eq!(iri.fragment(), None);
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriReferenceStr, validate::Error};
- /// let iri = IriReferenceStr::new("")?;
- /// assert_eq!(iri.fragment(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- pub fn fragment(&self) -> Option<&RiFragmentStr<S>> {
- trusted_parser::extract_fragment(self.as_str()).map(|fragment| {
- // SAFETY: `extract_fragment` returns the fragment part of an IRI,
- // and the returned string should have only valid characters since
- // is the substring of the source IRI.
- unsafe { RiFragmentStr::new_maybe_unchecked(fragment) }
- })
- }
-
- /// Returns the fragment part as a raw string slice if exists.
- ///
- /// A leading `#` character is truncated if the fragment part exists.
- ///
- /// # Examples
- ///
- /// If the IRI has a fragment part, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriReferenceStr, validate::Error};
- /// let iri = IriReferenceStr::new("foo://bar/baz?qux=quux#corge")?;
- /// assert_eq!(iri.fragment_str(), Some("corge"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriReferenceStr, validate::Error};
- /// let iri = IriReferenceStr::new("#foo")?;
- /// assert_eq!(iri.fragment_str(), Some("foo"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// When the fragment part exists but is empty string, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriReferenceStr, validate::Error};
- /// let iri = IriReferenceStr::new("foo://bar/baz?qux=quux#")?;
- /// assert_eq!(iri.fragment_str(), Some(""));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriReferenceStr, validate::Error};
- /// let iri = IriReferenceStr::new("#")?;
- /// assert_eq!(iri.fragment_str(), Some(""));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the IRI has no fragment, `None` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriReferenceStr, validate::Error};
- /// let iri = IriReferenceStr::new("foo://bar/baz?qux=quux")?;
- /// assert_eq!(iri.fragment(), None);
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriReferenceStr, validate::Error};
- /// let iri = IriReferenceStr::new("")?;
- /// assert_eq!(iri.fragment(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- pub fn fragment_str(&self) -> Option<&str> {
- trusted_parser::extract_fragment(self.as_str())
- }
-
- /// Returns the authority components.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("http://user:pass@example.com:8080/pathpath?queryquery")?;
- /// let authority = iri.authority_components()
- /// .expect("authority is available");
- /// assert_eq!(authority.userinfo(), Some("user:pass"));
- /// assert_eq!(authority.host(), "example.com");
- /// assert_eq!(authority.port(), Some("8080"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriReferenceStr;
- ///
- /// let iri = IriReferenceStr::new("foo//bar:baz")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_components(&self) -> Option<AuthorityComponents<'_>> {
- AuthorityComponents::from_iri(self)
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> RiReferenceString<S> {
- /// Returns the string as [`RiString`], if it is valid as an IRI.
- ///
- /// If it is not an IRI, then [`RiRelativeString`] is returned as `Err(_)`.
- ///
- /// [`RiRelativeString`]: struct.RiRelativeString.html
- /// [`RiString`]: struct.RiString.html
- pub fn into_iri(self) -> Result<RiString<S>, RiRelativeString<S>> {
- let s: String = self.into();
- // Check with `IRI` rule first, because of the syntax.
- //
- // > Some productions are ambiguous. The "first-match-wins" (a.k.a.
- // > "greedy") algorithm applies. For details, see [RFC3986].
- // >
- // > --- <https://tools.ietf.org/html/rfc3987#section-2.2>.
- if iri::<S>(&s).is_ok() {
- // SAFETY: just checked `s` is valid as an IRI.
- Ok(unsafe { RiString::new_always_unchecked(s) })
- } else {
- // SAFETY: if an IRI reference is not an IRI, then it is a relative IRI.
- // See the RFC 3987 syntax rule `IRI-reference = IRI / irelative-ref`.
- Err(unsafe { RiRelativeString::new_maybe_unchecked(s) })
- }
- }
-
- /// Returns the string as [`RiRelativeString`], if it is valid as an IRI.
- ///
- /// If it is not an IRI, then [`RiString`] is returned as `Err(_)`.
- ///
- /// [`RiRelativeString`]: struct.RiRelativeString.html
- /// [`RiString`]: struct.RiString.html
- pub fn into_relative_iri(self) -> Result<RiRelativeString<S>, RiString<S>> {
- match self.into_iri() {
- Ok(iri) => Err(iri),
- Err(relative) => Ok(relative),
- }
- }
-
- /// Sets the fragment part to the given string.
- ///
- /// Removes fragment part (and following `#` character) if `None` is given.
- pub fn set_fragment(&mut self, fragment: Option<&RiFragmentStr<S>>) {
- raw::set_fragment(&mut self.inner, fragment.map(AsRef::as_ref));
- debug_assert!(iri_reference::<S>(&self.inner).is_ok());
- }
-
- /// Removes the password completely (including separator colon) from `self` even if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriReferenceString;
- ///
- /// let mut iri = IriReferenceString::try_from("http://user:password@example.com/path?query")?;
- /// iri.remove_password_inline();
- /// assert_eq!(iri, "http://user@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// Even if the password is empty, the password and separator will be removed.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriReferenceString;
- ///
- /// let mut iri = IriReferenceString::try_from("http://user:@example.com/path?query")?;
- /// iri.remove_password_inline();
- /// assert_eq!(iri, "http://user@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn remove_password_inline(&mut self) {
- let pw_range = match password_range_to_hide(self.as_slice()) {
- Some(v) => v,
- None => return,
- };
- let separator_colon = pw_range.start - 1;
- // SAFETY: the IRI must be valid after the password component and
- // the leading separator colon is removed.
- unsafe {
- let buf = self.as_inner_mut();
- buf.drain(separator_colon..pw_range.end);
- debug_assert!(
- RiReferenceStr::<S>::new(buf).is_ok(),
- "[validity] the IRI must be valid after the password component is removed"
- );
- }
- }
-
- /// Replaces the non-empty password in `self` to the empty password.
- ///
- /// This leaves the separator colon if the password part was available.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriReferenceString;
- ///
- /// let mut iri = IriReferenceString::try_from("http://user:password@example.com/path?query")?;
- /// iri.remove_nonempty_password_inline();
- /// assert_eq!(iri, "http://user:@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the password is empty, it is left as is.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriReferenceString;
- ///
- /// let mut iri = IriReferenceString::try_from("http://user:@example.com/path?query")?;
- /// iri.remove_nonempty_password_inline();
- /// assert_eq!(iri, "http://user:@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn remove_nonempty_password_inline(&mut self) {
- let pw_range = match password_range_to_hide(self.as_slice()) {
- Some(v) if !v.is_empty() => v,
- _ => return,
- };
- debug_assert_eq!(
- self.as_str().as_bytes().get(pw_range.start - 1).copied(),
- Some(b':'),
- "[validity] the password component must be prefixed with a separator colon"
- );
- // SAFETY: the IRI must be valid after the password component is
- // replaced with the empty password.
- unsafe {
- let buf = self.as_inner_mut();
- buf.drain(pw_range);
- debug_assert!(
- RiReferenceStr::<S>::new(buf).is_ok(),
- "[validity] the IRI must be valid after the password component \
- is replaced with the empty password"
- );
- }
- }
-}
diff --git a/vendor/iri-string/src/types/generic/relative.rs b/vendor/iri-string/src/types/generic/relative.rs
deleted file mode 100644
index 2c1618b5..00000000
--- a/vendor/iri-string/src/types/generic/relative.rs
+++ /dev/null
@@ -1,571 +0,0 @@
-//! Relative IRI reference.
-
-use crate::components::AuthorityComponents;
-#[cfg(feature = "alloc")]
-use crate::mask_password::password_range_to_hide;
-use crate::mask_password::PasswordMasked;
-use crate::normalize::Normalized;
-use crate::parser::trusted as trusted_parser;
-#[cfg(feature = "alloc")]
-use crate::raw;
-use crate::resolve::FixedBaseResolver;
-use crate::spec::Spec;
-#[cfg(feature = "alloc")]
-use crate::types::RiReferenceString;
-use crate::types::{RiAbsoluteStr, RiFragmentStr, RiQueryStr, RiReferenceStr, RiStr};
-use crate::validate::relative_ref;
-
-define_custom_string_slice! {
- /// A borrowed slice of a relative IRI reference.
- ///
- /// This corresponds to [`irelative-ref` rule] in [RFC 3987]
- /// (and [`relative-ref` rule] in [RFC 3986]).
- /// The rule for `irelative-ref` is `irelative-part [ "?" iquery ] [ "#" ifragment ]`.
- ///
- /// # Valid values
- ///
- /// This type can have a relative IRI reference.
- ///
- /// ```
- /// # use iri_string::types::IriRelativeStr;
- /// assert!(IriRelativeStr::new("foo").is_ok());
- /// assert!(IriRelativeStr::new("foo/bar").is_ok());
- /// assert!(IriRelativeStr::new("/foo").is_ok());
- /// assert!(IriRelativeStr::new("//foo/bar").is_ok());
- /// assert!(IriRelativeStr::new("?foo").is_ok());
- /// assert!(IriRelativeStr::new("#foo").is_ok());
- /// assert!(IriRelativeStr::new("foo/bar?baz#qux").is_ok());
- /// // The first path component can have colon if the path is absolute.
- /// assert!(IriRelativeStr::new("/foo:bar/").is_ok());
- /// // Second or following path components can have colon.
- /// assert!(IriRelativeStr::new("foo/bar://baz/").is_ok());
- /// assert!(IriRelativeStr::new("./foo://bar").is_ok());
- /// ```
- ///
- /// Absolute form of a reference is not allowed.
- ///
- /// ```
- /// # use iri_string::types::IriRelativeStr;
- /// assert!(IriRelativeStr::new("https://example.com/").is_err());
- /// // The first path component cannot have colon, if the path is not absolute.
- /// assert!(IriRelativeStr::new("foo:bar").is_err());
- /// assert!(IriRelativeStr::new("foo:").is_err());
- /// assert!(IriRelativeStr::new("foo:/").is_err());
- /// assert!(IriRelativeStr::new("foo://").is_err());
- /// assert!(IriRelativeStr::new("foo:///").is_err());
- /// assert!(IriRelativeStr::new("foo:////").is_err());
- /// assert!(IriRelativeStr::new("foo://///").is_err());
- /// ```
- ///
- /// Some characters and sequences cannot used in an IRI reference.
- ///
- /// ```
- /// # use iri_string::types::IriRelativeStr;
- /// // `<` and `>` cannot directly appear in a relative IRI reference.
- /// assert!(IriRelativeStr::new("<not allowed>").is_err());
- /// // Broken percent encoding cannot appear in a relative IRI reference.
- /// assert!(IriRelativeStr::new("%").is_err());
- /// assert!(IriRelativeStr::new("%GG").is_err());
- /// ```
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`irelative-ref` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`relative-ref` rule]: https://tools.ietf.org/html/rfc3986#section-4.2
- struct RiRelativeStr {
- validator = relative_ref,
- expecting_msg = "Relative IRI reference string",
- }
-}
-
-#[cfg(feature = "alloc")]
-define_custom_string_owned! {
- /// An owned string of a relative IRI reference.
- ///
- /// This corresponds to [`irelative-ref` rule] in [RFC 3987]
- /// (and [`relative-ref` rule] in [RFC 3986]).
- /// The rule for `irelative-ref` is `irelative-part [ "?" iquery ] [ "#" ifragment ]`.
- ///
- /// For details, see the document for [`RiRelativeStr`].
- ///
- /// Enabled by `alloc` or `std` feature.
- ///
- /// [RFC 3986]: https://tools.ietf.org/html/rfc3986
- /// [RFC 3987]: https://tools.ietf.org/html/rfc3987
- /// [`irelative-ref` rule]: https://tools.ietf.org/html/rfc3987#section-2.2
- /// [`relative-ref` rule]: https://tools.ietf.org/html/rfc3986#section-4.2
- /// [`RiRelativeString`]: struct.RiRelativeString.html
- struct RiRelativeString {
- validator = relative_ref,
- slice = RiRelativeStr,
- expecting_msg = "Relative IRI reference string",
- }
-}
-
-impl<S: Spec> RiRelativeStr<S> {
- /// Returns resolved IRI against the given base IRI.
- ///
- /// For IRI reference resolution output examples, see [RFC 3986 section 5.4].
- ///
- /// If you are going to resolve multiple references against the common base,
- /// consider using [`FixedBaseResolver`].
- ///
- /// # Strictness
- ///
- /// The IRI parsers provided by this crate is strict (e.g. `http:g` is
- /// always interpreted as a composition of the scheme `http` and the path
- /// `g`), so backward compatible parsing and resolution are not provided.
- /// About parser and resolver strictness, see [RFC 3986 section 5.4.2]:
- ///
- /// > Some parsers allow the scheme name to be present in a relative
- /// > reference if it is the same as the base URI scheme. This is considered
- /// > to be a loophole in prior specifications of partial URI
- /// > [RFC1630](https://tools.ietf.org/html/rfc1630). Its use should be
- /// > avoided but is allowed for backward compatibility.
- /// >
- /// > --- <https://tools.ietf.org/html/rfc3986#section-5.4.2>
- ///
- /// # Failures
- ///
- /// This method itself does not fail, but IRI resolution without WHATWG URL
- /// Standard serialization can fail in some minor cases.
- ///
- /// To see examples of such unresolvable IRIs, visit the documentation
- /// for [`normalize`][`crate::normalize`] module.
- ///
- /// [RFC 3986 section 5.4]: https://tools.ietf.org/html/rfc3986#section-5.4
- /// [RFC 3986 section 5.4.2]: https://tools.ietf.org/html/rfc3986#section-5.4.2
- pub fn resolve_against<'a>(&'a self, base: &'a RiAbsoluteStr<S>) -> Normalized<'a, RiStr<S>> {
- FixedBaseResolver::new(base).resolve(self.as_ref())
- }
-
- /// Returns the proxy to the IRI with password masking feature.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::format::ToDedicatedString;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("//user:password@example.com/path?query")?;
- /// let masked = iri.mask_password();
- /// assert_eq!(masked.to_dedicated_string(), "//user:@example.com/path?query");
- ///
- /// assert_eq!(
- /// masked.replace_password("${password}").to_string(),
- /// "//user:${password}@example.com/path?query"
- /// );
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn mask_password(&self) -> PasswordMasked<'_, Self> {
- PasswordMasked::new(self)
- }
-}
-
-/// Components getters.
-impl<S: Spec> RiRelativeStr<S> {
- /// Returns the authority.
- ///
- /// The leading `//` is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("//example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.authority_str(), Some("example.com"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("foo//bar:baz")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_str(&self) -> Option<&str> {
- trusted_parser::extract_authority_relative(self.as_str())
- }
-
- /// Returns the path.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("//example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.path_str(), "/pathpath");
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("foo//bar:baz")?;
- /// assert_eq!(iri.path_str(), "foo//bar:baz");
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn path_str(&self) -> &str {
- trusted_parser::extract_path_relative(self.as_str())
- }
-
- /// Returns the query.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::{IriQueryStr, IriRelativeStr};
- ///
- /// let iri = IriRelativeStr::new("//example.com/pathpath?queryquery#fragfrag")?;
- /// let query = IriQueryStr::new("queryquery")?;
- /// assert_eq!(iri.query(), Some(query));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::{IriQueryStr, IriRelativeStr};
- ///
- /// let iri = IriRelativeStr::new("foo//bar:baz?")?;
- /// let query = IriQueryStr::new("")?;
- /// assert_eq!(iri.query(), Some(query));
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query(&self) -> Option<&RiQueryStr<S>> {
- trusted_parser::extract_query(self.as_str()).map(|query| {
- // SAFETY: `extract_query` returns the query part of an IRI, and the
- // returned string should have only valid characters since is the
- // substring of the source IRI.
- unsafe { RiQueryStr::new_maybe_unchecked(query) }
- })
- }
-
- /// Returns the query in a raw string slice.
- ///
- /// The leading question mark (`?`) is truncated.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("//example.com/pathpath?queryquery#fragfrag")?;
- /// assert_eq!(iri.query_str(), Some("queryquery"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("foo//bar:baz?")?;
- /// assert_eq!(iri.query_str(), Some(""));
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn query_str(&self) -> Option<&str> {
- trusted_parser::extract_query(self.as_str())
- }
-
- /// Returns the fragment part if exists.
- ///
- /// A leading `#` character is truncated if the fragment part exists.
- ///
- /// # Examples
- ///
- /// If the IRI has a fragment part, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriRelativeStr}, validate::Error};
- /// let iri = IriRelativeStr::new("?foo#bar")?;
- /// let fragment = IriFragmentStr::new("bar")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriRelativeStr}, validate::Error};
- /// let iri = IriRelativeStr::new("#foo")?;
- /// let fragment = IriFragmentStr::new("foo")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// When the fragment part exists but is empty string, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::{IriFragmentStr, IriRelativeStr}, validate::Error};
- /// let iri = IriRelativeStr::new("#")?;
- /// let fragment = IriFragmentStr::new("")?;
- /// assert_eq!(iri.fragment(), Some(fragment));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the IRI has no fragment, `None` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriRelativeStr, validate::Error};
- /// let iri = IriRelativeStr::new("")?;
- /// assert_eq!(iri.fragment(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- pub fn fragment(&self) -> Option<&RiFragmentStr<S>> {
- AsRef::<RiReferenceStr<S>>::as_ref(self).fragment()
- }
-
- /// Returns the fragment part as a raw string slice if exists.
- ///
- /// A leading `#` character is truncated if the fragment part exists.
- ///
- /// # Examples
- ///
- /// If the IRI has a fragment part, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriRelativeStr, validate::Error};
- /// let iri = IriRelativeStr::new("?foo#bar")?;
- /// assert_eq!(iri.fragment_str(), Some("bar"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriRelativeStr, validate::Error};
- /// let iri = IriRelativeStr::new("#foo")?;
- /// assert_eq!(iri.fragment_str(), Some("foo"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// When the fragment part exists but is empty string, `Some(_)` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriRelativeStr, validate::Error};
- /// let iri = IriRelativeStr::new("#")?;
- /// assert_eq!(iri.fragment_str(), Some(""));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the IRI has no fragment, `None` is returned.
- ///
- /// ```
- /// # use iri_string::{spec::IriSpec, types::IriRelativeStr, validate::Error};
- /// let iri = IriRelativeStr::new("")?;
- /// assert_eq!(iri.fragment(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- pub fn fragment_str(&self) -> Option<&str> {
- AsRef::<RiReferenceStr<S>>::as_ref(self).fragment_str()
- }
-
- /// Returns the authority components.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("//user:pass@example.com:8080/pathpath?queryquery")?;
- /// let authority = iri.authority_components()
- /// .expect("authority is available");
- /// assert_eq!(authority.userinfo(), Some("user:pass"));
- /// assert_eq!(authority.host(), "example.com");
- /// assert_eq!(authority.port(), Some("8080"));
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// use iri_string::types::IriRelativeStr;
- ///
- /// let iri = IriRelativeStr::new("foo//bar:baz")?;
- /// assert_eq!(iri.authority_str(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn authority_components(&self) -> Option<AuthorityComponents<'_>> {
- AuthorityComponents::from_iri(self.as_ref())
- }
-}
-
-#[cfg(feature = "alloc")]
-impl<S: Spec> RiRelativeString<S> {
- /// Sets the fragment part to the given string.
- ///
- /// Removes fragment part (and following `#` character) if `None` is given.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::{IriFragmentStr, IriRelativeString};
- ///
- /// let mut iri = IriRelativeString::try_from("//user:password@example.com/path?query#frag.old")?;
- /// assert_eq!(iri.fragment_str(), Some("frag.old"));
- ///
- /// iri.set_fragment(None);
- /// assert_eq!(iri.fragment(), None);
- ///
- /// let frag_new = IriFragmentStr::new("frag-new")?;
- /// iri.set_fragment(Some(frag_new));
- /// assert_eq!(iri.fragment_str(), Some("frag-new"));
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// Fragment can be empty, and it is distinguished from the absense of a fragment.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriRelativeString;
- ///
- /// let mut iri = IriRelativeString::try_from("/path#")?;
- /// assert_eq!(iri, "/path#");
- /// assert_eq!(iri.fragment_str(), Some(""), "Fragment is present and empty");
- ///
- /// iri.set_fragment(None);
- /// assert_eq!(iri, "/path", "Note that # is now removed");
- /// assert_eq!(iri.fragment_str(), None, "Fragment is absent");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn set_fragment(&mut self, fragment: Option<&RiFragmentStr<S>>) {
- raw::set_fragment(&mut self.inner, fragment.map(AsRef::as_ref));
- debug_assert!(relative_ref::<S>(&self.inner).is_ok());
- }
-
- /// Removes the password completely (including separator colon) from `self` even if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriRelativeString;
- ///
- /// let mut iri = IriRelativeString::try_from("//user:password@example.com/path?query")?;
- /// iri.remove_password_inline();
- /// assert_eq!(iri, "//user@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// Even if the password is empty, the password and separator will be removed.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriRelativeString;
- ///
- /// let mut iri = IriRelativeString::try_from("//user:@example.com/path?query")?;
- /// iri.remove_password_inline();
- /// assert_eq!(iri, "//user@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn remove_password_inline(&mut self) {
- let pw_range = match password_range_to_hide(self.as_slice().as_ref()) {
- Some(v) => v,
- None => return,
- };
- let separator_colon = pw_range.start - 1;
- // SAFETY: removing password component and the leading colon preserves
- // the IRI still syntactically valid.
- unsafe {
- let buf = self.as_inner_mut();
- buf.drain(separator_colon..pw_range.end);
- debug_assert!(
- RiRelativeStr::<S>::new(buf).is_ok(),
- "[validity] the IRI must be valid after the password component is removed"
- );
- }
- }
-
- /// Replaces the non-empty password in `self` to the empty password.
- ///
- /// This leaves the separator colon if the password part was available.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriRelativeString;
- ///
- /// let mut iri = IriRelativeString::try_from("//user:password@example.com/path?query")?;
- /// iri.remove_nonempty_password_inline();
- /// assert_eq!(iri, "//user:@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- ///
- /// If the password is empty, it is left as is.
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- /// use iri_string::types::IriRelativeString;
- ///
- /// let mut iri = IriRelativeString::try_from("//user:@example.com/path?query")?;
- /// iri.remove_nonempty_password_inline();
- /// assert_eq!(iri, "//user:@example.com/path?query");
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn remove_nonempty_password_inline(&mut self) {
- let pw_range = match password_range_to_hide(self.as_slice().as_ref()) {
- Some(v) if !v.is_empty() => v,
- _ => return,
- };
- debug_assert_eq!(
- self.as_str().as_bytes().get(pw_range.start - 1).copied(),
- Some(b':'),
- "[validity] the password component must be prefixed with a separator colon"
- );
- // SAFETY: the IRI must be valid after the password component is
- // replaced with the empty password.
- unsafe {
- let buf = self.as_inner_mut();
- buf.drain(pw_range);
- debug_assert!(
- RiRelativeStr::<S>::new(buf).is_ok(),
- "[validity] the IRI must be valid after the password component \
- is replaced with the empty password"
- );
- }
- }
-}
-
-impl_trivial_conv_between_iri! {
- from_slice: RiRelativeStr,
- from_owned: RiRelativeString,
- to_slice: RiReferenceStr,
- to_owned: RiReferenceString,
-}
diff --git a/vendor/iri-string/src/types/iri.rs b/vendor/iri-string/src/types/iri.rs
deleted file mode 100644
index f89be7c7..00000000
--- a/vendor/iri-string/src/types/iri.rs
+++ /dev/null
@@ -1,382 +0,0 @@
-//! IRI-specific implementations.
-
-#[cfg(feature = "alloc")]
-use alloc::collections::TryReserveError;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use alloc::string::String;
-
-#[cfg(feature = "alloc")]
-use crate::convert::try_percent_encode_iri_inline;
-use crate::convert::MappedToUri;
-use crate::spec::IriSpec;
-use crate::types::{
- RiAbsoluteStr, RiFragmentStr, RiQueryStr, RiReferenceStr, RiRelativeStr, RiStr,
-};
-#[cfg(feature = "alloc")]
-use crate::types::{
- RiAbsoluteString, RiFragmentString, RiQueryString, RiReferenceString, RiRelativeString,
- RiString,
-};
-use crate::types::{
- UriAbsoluteStr, UriFragmentStr, UriQueryStr, UriReferenceStr, UriRelativeStr, UriStr,
-};
-#[cfg(feature = "alloc")]
-use crate::types::{
- UriAbsoluteString, UriFragmentString, UriQueryString, UriReferenceString, UriRelativeString,
- UriString,
-};
-
-/// A type alias for [`RiAbsoluteStr`]`<`[`IriSpec`]`>`.
-pub type IriAbsoluteStr = RiAbsoluteStr<IriSpec>;
-
-/// A type alias for [`RiAbsoluteString`]`<`[`IriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type IriAbsoluteString = RiAbsoluteString<IriSpec>;
-
-/// A type alias for [`RiFragmentStr`]`<`[`IriSpec`]`>`.
-pub type IriFragmentStr = RiFragmentStr<IriSpec>;
-
-/// A type alias for [`RiFragmentString`]`<`[`IriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type IriFragmentString = RiFragmentString<IriSpec>;
-
-/// A type alias for [`RiStr`]`<`[`IriSpec`]`>`.
-pub type IriStr = RiStr<IriSpec>;
-
-/// A type alias for [`RiString`]`<`[`IriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type IriString = RiString<IriSpec>;
-
-/// A type alias for [`RiReferenceStr`]`<`[`IriSpec`]`>`.
-pub type IriReferenceStr = RiReferenceStr<IriSpec>;
-
-/// A type alias for [`RiReferenceString`]`<`[`IriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type IriReferenceString = RiReferenceString<IriSpec>;
-
-/// A type alias for [`RiRelativeStr`]`<`[`IriSpec`]`>`.
-pub type IriRelativeStr = RiRelativeStr<IriSpec>;
-
-/// A type alias for [`RiRelativeString`]`<`[`IriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type IriRelativeString = RiRelativeString<IriSpec>;
-
-/// A type alias for [`RiQueryStr`]`<`[`IriSpec`]`>`.
-pub type IriQueryStr = RiQueryStr<IriSpec>;
-
-/// A type alias for [`RiQueryString`]`<`[`IriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type IriQueryString = RiQueryString<IriSpec>;
-
-/// Implements the conversion from an IRI into a URI.
-macro_rules! impl_conversion_between_uri {
- (
- $ty_owned_iri:ident,
- $ty_owned_uri:ident,
- $ty_borrowed_iri:ident,
- $ty_borrowed_uri:ident,
- $example_iri:expr,
- $example_uri:expr
- ) => {
- /// Conversion from an IRI into a URI.
- impl $ty_borrowed_iri {
- /// Percent-encodes the IRI into a valid URI that identifies the equivalent resource.
- ///
- /// If you need more precise control over memory allocation and buffer
- /// handling, use [`MappedToUri`][`crate::convert::MappedToUri`] type.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// # #[cfg(feature = "alloc")] {
- #[doc = concat!("use iri_string::format::ToDedicatedString;")]
- #[doc = concat!("use iri_string::types::{", stringify!($ty_borrowed_iri), ", ", stringify!($ty_owned_uri), "};")]
- ///
- #[doc = concat!("let iri = ", stringify!($ty_borrowed_iri), "::new(", stringify!($example_iri), ")?;")]
- /// // Type annotation here is not necessary.
- #[doc = concat!("let uri: ", stringify!($ty_owned_uri), " = iri.encode_to_uri().to_dedicated_string();")]
- #[doc = concat!("assert_eq!(uri, ", stringify!($example_uri), ");")]
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn encode_to_uri(&self) -> MappedToUri<'_, Self> {
- MappedToUri::from(self)
- }
-
- /// Converts an IRI into a URI without modification, if possible.
- ///
- /// This is semantically equivalent to
- #[doc = concat!("`", stringify!($ty_borrowed_uri), "::new(self.as_str()).ok()`.")]
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- #[doc = concat!("use iri_string::types::{", stringify!($ty_borrowed_iri), ", ", stringify!($ty_borrowed_uri), "};")]
- ///
- #[doc = concat!("let ascii_iri = ", stringify!($ty_borrowed_iri), "::new(", stringify!($example_uri), ")?;")]
- /// assert_eq!(
- /// ascii_iri.as_uri().map(AsRef::as_ref),
- #[doc = concat!(" Some(", stringify!($example_uri), ")")]
- /// );
- ///
- #[doc = concat!("let nonascii_iri = ", stringify!($ty_borrowed_iri), "::new(", stringify!($example_iri), ")?;")]
- /// assert_eq!(nonascii_iri.as_uri(), None);
- /// # Ok::<_, Error>(())
- /// ```
- #[must_use]
- pub fn as_uri(&self) -> Option<&$ty_borrowed_uri> {
- if !self.as_str().is_ascii() {
- return None;
- }
- debug_assert!(
- <$ty_borrowed_uri>::new(self.as_str()).is_ok(),
- "[consistency] the ASCII-only IRI must also be a valid URI"
- );
- // SAFETY: An ASCII-only IRI is a URI.
- // URI (by `UriSpec`) is a subset of IRI (by `IriSpec`),
- // and the difference is that URIs can only have ASCII characters.
- let uri = unsafe { <$ty_borrowed_uri>::new_maybe_unchecked(self.as_str()) };
- Some(uri)
- }
- }
-
- /// Conversion from an IRI into a URI.
- #[cfg(feature = "alloc")]
- impl $ty_owned_iri {
- /// Percent-encodes the IRI into a valid URI that identifies the equivalent resource.
- ///
- /// After the encode, the IRI is also a valid URI.
- ///
- /// If you want a new URI string rather than modifying the IRI
- /// string, or if you need more precise control over memory
- /// allocation and buffer handling, use
- #[doc = concat!("[`encode_to_uri`][`", stringify!($ty_borrowed_iri), "::encode_to_uri`]")]
- /// method.
- ///
- /// # Panics
- ///
- /// Panics if the memory allocation failed.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// #[cfg(feature = "alloc")] {
- #[doc = concat!("use iri_string::types::", stringify!($ty_owned_iri), ";")]
- ///
- #[doc = concat!("let mut iri = ", stringify!($ty_owned_iri), "::try_from(", stringify!($example_iri), ")?;")]
- /// iri.encode_to_uri_inline();
- #[doc = concat!("assert_eq!(iri, ", stringify!($example_uri), ");")]
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn encode_to_uri_inline(&mut self) {
- self.try_encode_to_uri_inline()
- .expect("failed to allocate memory");
- }
-
- /// Percent-encodes the IRI into a valid URI that identifies the equivalent resource.
- ///
- /// After the encode, the IRI is also a valid URI.
- ///
- /// If you want a new URI string rather than modifying the IRI
- /// string, or if you need more precise control over memory
- /// allocation and buffer handling, use
- #[doc = concat!("[`encode_to_uri`][`", stringify!($ty_borrowed_iri), "::encode_to_uri`]")]
- /// method.
- ///
- // TODO: This seems true as of this writing, but is this guaranteed? See
- // <https://users.rust-lang.org/t/does-try-reserve-guarantees-that-the-content-is-preserved-on-allocation-failure/77446>.
- // /// If the memory allocation failed, the content is preserved without modification.
- // ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// #[cfg(feature = "alloc")] {
- #[doc = concat!("use iri_string::types::", stringify!($ty_owned_iri), ";")]
- ///
- #[doc = concat!("let mut iri = ", stringify!($ty_owned_iri), "::try_from(", stringify!($example_iri), ")?;")]
- /// iri.try_encode_to_uri_inline()
- /// .expect("failed to allocate memory");
- #[doc = concat!("assert_eq!(iri, ", stringify!($example_uri), ");")]
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- pub fn try_encode_to_uri_inline(&mut self) -> Result<(), TryReserveError> {
- // SAFETY: IRI is valid after it is encoded to URI (by percent encoding).
- unsafe {
- let buf = self.as_inner_mut();
- try_percent_encode_iri_inline(buf)?;
- }
- debug_assert!(
- <$ty_borrowed_iri>::new(self.as_str()).is_ok(),
- "[consistency] the content must be valid at any time"
- );
- Ok(())
- }
-
- /// Percent-encodes the IRI into a valid URI that identifies the equivalent resource.
- ///
- /// If you want a new URI string rather than modifying the IRI
- /// string, or if you need more precise control over memory
- /// allocation and buffer handling, use
- #[doc = concat!("[`encode_to_uri`][`", stringify!($ty_borrowed_iri), "::encode_to_uri`]")]
- /// method.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// #[cfg(feature = "alloc")] {
- #[doc = concat!("use iri_string::types::{", stringify!($ty_owned_iri), ", ", stringify!($ty_owned_uri), "};")]
- ///
- #[doc = concat!("let iri = ", stringify!($ty_owned_iri), "::try_from(", stringify!($example_iri), ")?;")]
- /// // Type annotation here is not necessary.
- #[doc = concat!("let uri: ", stringify!($ty_owned_uri), " = iri.encode_into_uri();")]
- #[doc = concat!("assert_eq!(uri, ", stringify!($example_uri), ");")]
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- #[inline]
- #[must_use]
- pub fn encode_into_uri(self) -> $ty_owned_uri {
- self.try_encode_into_uri()
- .expect("failed to allocate memory")
- }
-
- /// Percent-encodes the IRI into a valid URI that identifies the equivalent resource.
- ///
- /// If you want a new URI string rather than modifying the IRI
- /// string, or if you need more precise control over memory
- /// allocation and buffer handling, use
- #[doc = concat!("[`encode_to_uri`][`", stringify!($ty_borrowed_iri), "::encode_to_uri`]")]
- /// method.
- ///
- // TODO: This seems true as of this writing, but is this guaranteed? See
- // <https://users.rust-lang.org/t/does-try-reserve-guarantees-that-the-content-is-preserved-on-allocation-failure/77446>.
- // /// If the memory allocation failed, the content is preserved without modification.
- // ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- /// #[cfg(feature = "alloc")] {
- #[doc = concat!("use iri_string::types::{", stringify!($ty_owned_iri), ", ", stringify!($ty_owned_uri), "};")]
- ///
- #[doc = concat!("let iri = ", stringify!($ty_owned_iri), "::try_from(", stringify!($example_iri), ")?;")]
- /// // Type annotation here is not necessary.
- #[doc = concat!("let uri: ", stringify!($ty_owned_uri), " = iri.try_encode_into_uri()")]
- /// .expect("failed to allocate memory");
- #[doc = concat!("assert_eq!(uri, ", stringify!($example_uri), ");")]
- /// # }
- /// # Ok::<_, Error>(())
- /// ```
- pub fn try_encode_into_uri(mut self) -> Result<$ty_owned_uri, TryReserveError> {
- self.try_encode_to_uri_inline()?;
- let s: String = self.into();
- debug_assert!(
- <$ty_borrowed_uri>::new(s.as_str()).is_ok(),
- "[consistency] the encoded IRI must also be a valid URI"
- );
- // SAFETY: An ASCII-only IRI is a URI.
- // URI (by `UriSpec`) is a subset of IRI (by `IriSpec`),
- // and the difference is that URIs can only have ASCII characters.
- let uri = unsafe { <$ty_owned_uri>::new_maybe_unchecked(s) };
- Ok(uri)
- }
-
- /// Converts an IRI into a URI without modification, if possible.
- ///
- /// # Examples
- ///
- /// ```
- /// # use iri_string::validate::Error;
- #[doc = concat!("use iri_string::types::{", stringify!($ty_owned_iri), ", ", stringify!($ty_owned_uri), "};")]
- ///
- #[doc = concat!("let ascii_iri = ", stringify!($ty_owned_iri), "::try_from(", stringify!($example_uri), ")?;")]
- /// assert_eq!(
- /// ascii_iri.try_into_uri().map(|uri| uri.to_string()),
- #[doc = concat!(" Ok(", stringify!($example_uri), ".to_string())")]
- /// );
- ///
- #[doc = concat!("let nonascii_iri = ", stringify!($ty_owned_iri), "::try_from(", stringify!($example_iri), ")?;")]
- /// assert_eq!(
- /// nonascii_iri.try_into_uri().map_err(|iri| iri.to_string()),
- #[doc = concat!(" Err(", stringify!($example_iri), ".to_string())")]
- /// );
- /// # Ok::<_, Error>(())
- /// ```
- pub fn try_into_uri(self) -> Result<$ty_owned_uri, $ty_owned_iri> {
- if !self.as_str().is_ascii() {
- return Err(self);
- }
- let s: String = self.into();
- debug_assert!(
- <$ty_borrowed_uri>::new(s.as_str()).is_ok(),
- "[consistency] the ASCII-only IRI must also be a valid URI"
- );
- // SAFETY: An ASCII-only IRI is a URI.
- // URI (by `UriSpec`) is a subset of IRI (by `IriSpec`),
- // and the difference is that URIs can only have ASCII characters.
- let uri = unsafe { <$ty_owned_uri>::new_maybe_unchecked(s) };
- Ok(uri)
- }
- }
- };
-}
-
-impl_conversion_between_uri!(
- IriAbsoluteString,
- UriAbsoluteString,
- IriAbsoluteStr,
- UriAbsoluteStr,
- "http://example.com/?alpha=\u{03B1}",
- "http://example.com/?alpha=%CE%B1"
-);
-impl_conversion_between_uri!(
- IriReferenceString,
- UriReferenceString,
- IriReferenceStr,
- UriReferenceStr,
- "http://example.com/?alpha=\u{03B1}",
- "http://example.com/?alpha=%CE%B1"
-);
-impl_conversion_between_uri!(
- IriRelativeString,
- UriRelativeString,
- IriRelativeStr,
- UriRelativeStr,
- "../?alpha=\u{03B1}",
- "../?alpha=%CE%B1"
-);
-impl_conversion_between_uri!(
- IriString,
- UriString,
- IriStr,
- UriStr,
- "http://example.com/?alpha=\u{03B1}",
- "http://example.com/?alpha=%CE%B1"
-);
-impl_conversion_between_uri!(
- IriQueryString,
- UriQueryString,
- IriQueryStr,
- UriQueryStr,
- "alpha-is-\u{03B1}",
- "alpha-is-%CE%B1"
-);
-impl_conversion_between_uri!(
- IriFragmentString,
- UriFragmentString,
- IriFragmentStr,
- UriFragmentStr,
- "alpha-is-\u{03B1}",
- "alpha-is-%CE%B1"
-);
diff --git a/vendor/iri-string/src/types/uri.rs b/vendor/iri-string/src/types/uri.rs
deleted file mode 100644
index 682a971c..00000000
--- a/vendor/iri-string/src/types/uri.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-//! URI-specific implementations.
-
-use crate::spec::UriSpec;
-use crate::types::{
- IriAbsoluteStr, IriFragmentStr, IriQueryStr, IriReferenceStr, IriRelativeStr, IriStr,
- RiAbsoluteStr, RiFragmentStr, RiQueryStr, RiReferenceStr, RiRelativeStr, RiStr,
-};
-#[cfg(feature = "alloc")]
-use crate::types::{
- IriAbsoluteString, IriFragmentString, IriQueryString, IriReferenceString, IriRelativeString,
- IriString, RiAbsoluteString, RiFragmentString, RiQueryString, RiReferenceString,
- RiRelativeString, RiString,
-};
-
-/// A type alias for [`RiAbsoluteStr`]`<`[`UriSpec`]`>`.
-pub type UriAbsoluteStr = RiAbsoluteStr<UriSpec>;
-
-/// A type alias for [`RiAbsoluteString`]`<`[`UriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type UriAbsoluteString = RiAbsoluteString<UriSpec>;
-
-/// A type alias for [`RiFragmentStr`]`<`[`UriSpec`]`>`.
-pub type UriFragmentStr = RiFragmentStr<UriSpec>;
-
-/// A type alias for [`RiFragmentString`]`<`[`UriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type UriFragmentString = RiFragmentString<UriSpec>;
-
-/// A type alias for [`RiStr`]`<`[`UriSpec`]`>`.
-pub type UriStr = RiStr<UriSpec>;
-
-/// A type alias for [`RiString`]`<`[`UriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type UriString = RiString<UriSpec>;
-
-/// A type alias for [`RiReferenceStr`]`<`[`UriSpec`]`>`.
-pub type UriReferenceStr = RiReferenceStr<UriSpec>;
-
-/// A type alias for [`RiReferenceString`]`<`[`UriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type UriReferenceString = RiReferenceString<UriSpec>;
-
-/// A type alias for [`RiRelativeStr`]`<`[`UriSpec`]`>`.
-pub type UriRelativeStr = RiRelativeStr<UriSpec>;
-
-/// A type alias for [`RiRelativeString`]`<`[`UriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type UriRelativeString = RiRelativeString<UriSpec>;
-
-/// A type alias for [`RiQueryStr`]`<`[`UriSpec`]`>`.
-pub type UriQueryStr = RiQueryStr<UriSpec>;
-
-/// A type alias for [`RiQueryString`]`<`[`UriSpec`]`>`.
-#[cfg(feature = "alloc")]
-pub type UriQueryString = RiQueryString<UriSpec>;
-
-/// Implements the trivial conversions between a URI and an IRI.
-macro_rules! impl_conversions_between_iri {
- (
- $borrowed_uri:ident,
- $owned_uri:ident,
- $borrowed_iri:ident,
- $owned_iri:ident,
- ) => {
- impl AsRef<$borrowed_iri> for $borrowed_uri {
- fn as_ref(&self) -> &$borrowed_iri {
- // SAFETY: A valid URI is also a valid IRI.
- unsafe { <$borrowed_iri>::new_maybe_unchecked(self.as_str()) }
- }
- }
-
- #[cfg(feature = "alloc")]
- impl From<$owned_uri> for $owned_iri {
- #[inline]
- fn from(uri: $owned_uri) -> Self {
- // SAFETY: A valid URI is also a valid IRI.
- unsafe { Self::new_maybe_unchecked(uri.into()) }
- }
- }
-
- #[cfg(feature = "alloc")]
- impl AsRef<$borrowed_iri> for $owned_uri {
- fn as_ref(&self) -> &$borrowed_iri {
- AsRef::<$borrowed_uri>::as_ref(self).as_ref()
- }
- }
- };
-}
-
-impl_conversions_between_iri!(
- UriAbsoluteStr,
- UriAbsoluteString,
- IriAbsoluteStr,
- IriAbsoluteString,
-);
-impl_conversions_between_iri!(
- UriReferenceStr,
- UriReferenceString,
- IriReferenceStr,
- IriReferenceString,
-);
-impl_conversions_between_iri!(
- UriRelativeStr,
- UriRelativeString,
- IriRelativeStr,
- IriRelativeString,
-);
-impl_conversions_between_iri!(UriStr, UriString, IriStr, IriString,);
-impl_conversions_between_iri!(UriQueryStr, UriQueryString, IriQueryStr, IriQueryString,);
-impl_conversions_between_iri!(
- UriFragmentStr,
- UriFragmentString,
- IriFragmentStr,
- IriFragmentString,
-);
diff --git a/vendor/iri-string/src/validate.rs b/vendor/iri-string/src/validate.rs
deleted file mode 100644
index efaa7efd..00000000
--- a/vendor/iri-string/src/validate.rs
+++ /dev/null
@@ -1,358 +0,0 @@
-//! Validators.
-
-use core::fmt;
-
-#[cfg(feature = "std")]
-use std::error;
-
-use crate::parser::validate as parser;
-use crate::spec::Spec;
-
-/// Resource identifier validation error.
-// Note that this type should implement `Copy` trait.
-// To return additional non-`Copy` data as an error, use wrapper type
-// (as `std::string::FromUtf8Error` contains `std::str::Utf8Error`).
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct Error(());
-
-impl Error {
- /// Creates a new `Error`.
- ///
- /// For internal use.
- #[inline]
- #[must_use]
- pub(crate) fn new() -> Self {
- Error(())
- }
-}
-
-impl fmt::Display for Error {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("Invalid IRI")
- }
-}
-
-#[cfg(feature = "std")]
-impl error::Error for Error {}
-
-/// Validates [IRI][uri].
-///
-/// This validator corresponds to [`RiStr`] and [`RiString`] types.
-///
-/// # Examples
-///
-/// This type can have an IRI (which is absolute, and may have fragment part).
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::iri};
-/// assert!(iri::<UriSpec>("https://user:pass@example.com:8080").is_ok());
-/// assert!(iri::<UriSpec>("https://example.com/").is_ok());
-/// assert!(iri::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
-/// assert!(iri::<UriSpec>("https://example.com/foo?bar=baz#qux").is_ok());
-/// assert!(iri::<UriSpec>("foo:bar").is_ok());
-/// assert!(iri::<UriSpec>("foo:").is_ok());
-/// // `foo://.../` below are all allowed. See the crate documentation for detail.
-/// assert!(iri::<UriSpec>("foo:/").is_ok());
-/// assert!(iri::<UriSpec>("foo://").is_ok());
-/// assert!(iri::<UriSpec>("foo:///").is_ok());
-/// assert!(iri::<UriSpec>("foo:////").is_ok());
-/// assert!(iri::<UriSpec>("foo://///").is_ok());
-/// ```
-///
-/// Relative IRI reference is not allowed.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::iri};
-/// // This is relative path.
-/// assert!(iri::<UriSpec>("foo/bar").is_err());
-/// // `/foo/bar` is an absolute path, but it is authority-relative.
-/// assert!(iri::<UriSpec>("/foo/bar").is_err());
-/// // `//foo/bar` is termed "network-path reference",
-/// // or usually called "protocol-relative reference".
-/// assert!(iri::<UriSpec>("//foo/bar").is_err());
-/// // Same-document reference is relative.
-/// assert!(iri::<UriSpec>("#foo").is_err());
-/// // Empty string is not a valid absolute IRI.
-/// assert!(iri::<UriSpec>("").is_err());
-/// ```
-///
-/// Some characters and sequences cannot used in an IRI.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::iri};
-/// // `<` and `>` cannot directly appear in an IRI.
-/// assert!(iri::<UriSpec>("<not allowed>").is_err());
-/// // Broken percent encoding cannot appear in an IRI.
-/// assert!(iri::<UriSpec>("%").is_err());
-/// assert!(iri::<UriSpec>("%GG").is_err());
-/// ```
-///
-/// [uri]: https://tools.ietf.org/html/rfc3986#section-3
-/// [`RiStr`]: ../types/struct.RiStr.html
-/// [`RiString`]: ../types/struct.RiString.html
-pub fn iri<S: Spec>(s: &str) -> Result<(), Error> {
- parser::validate_uri::<S>(s)
-}
-
-/// Validates [IRI reference][uri-reference].
-///
-/// This validator corresponds to [`RiReferenceStr`] and [`RiReferenceString`] types.
-///
-/// # Examples
-///
-/// This type can have an IRI reference (which can be absolute or relative).
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::iri_reference};
-/// assert!(iri_reference::<UriSpec>("https://user:pass@example.com:8080").is_ok());
-/// assert!(iri_reference::<UriSpec>("https://example.com/").is_ok());
-/// assert!(iri_reference::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
-/// assert!(iri_reference::<UriSpec>("https://example.com/foo?bar=baz#qux").is_ok());
-/// assert!(iri_reference::<UriSpec>("foo:bar").is_ok());
-/// assert!(iri_reference::<UriSpec>("foo:").is_ok());
-/// // `foo://.../` below are all allowed. See the crate documentation for detail.
-/// assert!(iri_reference::<UriSpec>("foo:/").is_ok());
-/// assert!(iri_reference::<UriSpec>("foo://").is_ok());
-/// assert!(iri_reference::<UriSpec>("foo:///").is_ok());
-/// assert!(iri_reference::<UriSpec>("foo:////").is_ok());
-/// assert!(iri_reference::<UriSpec>("foo://///").is_ok());
-/// assert!(iri_reference::<UriSpec>("foo/bar").is_ok());
-/// assert!(iri_reference::<UriSpec>("/foo/bar").is_ok());
-/// assert!(iri_reference::<UriSpec>("//foo/bar").is_ok());
-/// assert!(iri_reference::<UriSpec>("#foo").is_ok());
-/// ```
-///
-/// Some characters and sequences cannot used in an IRI reference.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::iri_reference};
-/// // `<` and `>` cannot directly appear in an IRI reference.
-/// assert!(iri_reference::<UriSpec>("<not allowed>").is_err());
-/// // Broken percent encoding cannot appear in an IRI reference.
-/// assert!(iri_reference::<UriSpec>("%").is_err());
-/// assert!(iri_reference::<UriSpec>("%GG").is_err());
-/// ```
-///
-/// [uri-reference]: https://tools.ietf.org/html/rfc3986#section-4.1
-/// [`RiReferenceStr`]: ../types/struct.RiReferenceStr.html
-/// [`RiReferenceString`]: ../types/struct.RiReferenceString.html
-pub fn iri_reference<S: Spec>(s: &str) -> Result<(), Error> {
- parser::validate_uri_reference::<S>(s)
-}
-
-/// Validates [absolute IRI][absolute-uri].
-///
-/// This validator corresponds to [`RiAbsoluteStr`] and [`RiAbsoluteString`] types.
-///
-/// # Examples
-///
-/// This type can have an absolute IRI without fragment part.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::absolute_iri};
-/// assert!(absolute_iri::<UriSpec>("https://example.com/foo?bar=baz").is_ok());
-/// assert!(absolute_iri::<UriSpec>("foo:bar").is_ok());
-/// // Scheme `foo` and empty path.
-/// assert!(absolute_iri::<UriSpec>("foo:").is_ok());
-/// // `foo://.../` below are all allowed. See the crate documentation for detail.
-/// assert!(absolute_iri::<UriSpec>("foo:/").is_ok());
-/// assert!(absolute_iri::<UriSpec>("foo://").is_ok());
-/// assert!(absolute_iri::<UriSpec>("foo:///").is_ok());
-/// assert!(absolute_iri::<UriSpec>("foo:////").is_ok());
-/// assert!(absolute_iri::<UriSpec>("foo://///").is_ok());
-///
-/// ```
-///
-/// Relative IRI is not allowed.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::absolute_iri};
-/// // This is relative path.
-/// assert!(absolute_iri::<UriSpec>("foo/bar").is_err());
-/// // `/foo/bar` is an absolute path, but it is authority-relative.
-/// assert!(absolute_iri::<UriSpec>("/foo/bar").is_err());
-/// // `//foo/bar` is termed "network-path reference",
-/// // or usually called "protocol-relative reference".
-/// assert!(absolute_iri::<UriSpec>("//foo/bar").is_err());
-/// // Empty string is not a valid absolute IRI.
-/// assert!(absolute_iri::<UriSpec>("").is_err());
-/// ```
-///
-/// Fragment part (such as trailing `#foo`) is not allowed.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::absolute_iri};
-/// // Fragment part is not allowed.
-/// assert!(absolute_iri::<UriSpec>("https://example.com/foo?bar=baz#qux").is_err());
-/// ```
-///
-/// Some characters and sequences cannot used in an absolute IRI.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::absolute_iri};
-/// // `<` and `>` cannot directly appear in an absolute IRI.
-/// assert!(absolute_iri::<UriSpec>("<not allowed>").is_err());
-/// // Broken percent encoding cannot appear in an absolute IRI.
-/// assert!(absolute_iri::<UriSpec>("%").is_err());
-/// assert!(absolute_iri::<UriSpec>("%GG").is_err());
-/// ```
-///
-/// [absolute-uri]: https://tools.ietf.org/html/rfc3986#section-4.3
-/// [`RiAbsoluteStr`]: ../types/struct.RiAbsoluteStr.html
-/// [`RiAbsoluteString`]: ../types/struct.RiAbsoluteString.html
-pub fn absolute_iri<S: Spec>(s: &str) -> Result<(), Error> {
- parser::validate_absolute_uri::<S>(s)
-}
-
-/// Validates [relative reference][relative-ref].
-///
-/// This validator corresponds to [`RiRelativeStr`] and [`RiRelativeString`] types.
-///
-/// # Valid values
-///
-/// This type can have a relative IRI reference.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::relative_ref};
-/// assert!(relative_ref::<UriSpec>("foo").is_ok());
-/// assert!(relative_ref::<UriSpec>("foo/bar").is_ok());
-/// assert!(relative_ref::<UriSpec>("/foo").is_ok());
-/// assert!(relative_ref::<UriSpec>("//foo/bar").is_ok());
-/// assert!(relative_ref::<UriSpec>("?foo").is_ok());
-/// assert!(relative_ref::<UriSpec>("#foo").is_ok());
-/// assert!(relative_ref::<UriSpec>("foo/bar?baz#qux").is_ok());
-/// // The first path component can have colon if the path is absolute.
-/// assert!(relative_ref::<UriSpec>("/foo:bar/").is_ok());
-/// // Second or following path components can have colon.
-/// assert!(relative_ref::<UriSpec>("foo/bar://baz/").is_ok());
-/// assert!(relative_ref::<UriSpec>("./foo://bar").is_ok());
-/// ```
-///
-/// Absolute form of a reference is not allowed.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::relative_ref};
-/// assert!(relative_ref::<UriSpec>("https://example.com/").is_err());
-/// // The first path component cannot have colon, if the path is not absolute.
-/// assert!(relative_ref::<UriSpec>("foo:bar").is_err());
-/// assert!(relative_ref::<UriSpec>("foo:").is_err());
-/// assert!(relative_ref::<UriSpec>("foo:/").is_err());
-/// assert!(relative_ref::<UriSpec>("foo://").is_err());
-/// assert!(relative_ref::<UriSpec>("foo:///").is_err());
-/// assert!(relative_ref::<UriSpec>("foo:////").is_err());
-/// assert!(relative_ref::<UriSpec>("foo://///").is_err());
-/// ```
-///
-/// Some characters and sequences cannot used in an IRI reference.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::relative_ref};
-/// // `<` and `>` cannot directly appear in a relative IRI reference.
-/// assert!(relative_ref::<UriSpec>("<not allowed>").is_err());
-/// // Broken percent encoding cannot appear in a relative IRI reference.
-/// assert!(relative_ref::<UriSpec>("%").is_err());
-/// assert!(relative_ref::<UriSpec>("%GG").is_err());
-/// ```
-///
-/// [relative-ref]: https://tools.ietf.org/html/rfc3986#section-4.2
-/// [`RiRelativeStr`]: ../types/struct.RiRelativeStr.html
-/// [`RiRelativeString`]: ../types/struct.RiRelativeString.html
-pub fn relative_ref<S: Spec>(s: &str) -> Result<(), Error> {
- parser::validate_relative_ref::<S>(s)
-}
-
-/// Validates [IRI path][path].
-///
-/// [path]: https://tools.ietf.org/html/rfc3986#section-3.3
-pub fn path<S: Spec>(s: &str) -> Result<(), Error> {
- parser::validate_path::<S>(s)
-}
-
-/// Validates [IRI query][query].
-///
-/// This validator corresponds to [`RiQueryStr`] and [`RiQueryString`] types.
-///
-/// Note that the first `?` character in an IRI is not a part of a query.
-/// For example, `https://example.com/?foo#bar` has a query `foo`, **not** `?foo`.
-///
-/// # Examples
-///
-/// This type can have an IRI query.
-/// Note that the IRI `foo://bar/baz?qux#quux` has the query `qux`, **not** `?qux`.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::query};
-/// assert!(query::<UriSpec>("").is_ok());
-/// assert!(query::<UriSpec>("foo").is_ok());
-/// assert!(query::<UriSpec>("foo/bar").is_ok());
-/// assert!(query::<UriSpec>("/foo/bar").is_ok());
-/// assert!(query::<UriSpec>("//foo/bar").is_ok());
-/// assert!(query::<UriSpec>("https://user:pass@example.com:8080").is_ok());
-/// assert!(query::<UriSpec>("https://example.com/").is_ok());
-/// // Question sign `?` can appear in an IRI query.
-/// assert!(query::<UriSpec>("query?again").is_ok());
-/// ```
-///
-/// Some characters and sequences cannot used in a query.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::query};
-/// // `<` and `>` cannot directly appear in an IRI reference.
-/// assert!(query::<UriSpec>("<not allowed>").is_err());
-/// // Broken percent encoding cannot appear in an IRI reference.
-/// assert!(query::<UriSpec>("%").is_err());
-/// assert!(query::<UriSpec>("%GG").is_err());
-/// // Hash sign `#` cannot appear in an IRI query.
-/// assert!(query::<UriSpec>("#hash").is_err());
-/// ```
-///
-/// [query]: https://tools.ietf.org/html/rfc3986#section-3.4
-/// [`RiQueryStr`]: ../types/struct.RiQueryStr.html
-/// [`RiQueryString`]: ../types/struct.RiQueryString.html
-pub fn query<S: Spec>(s: &str) -> Result<(), Error> {
- parser::validate_query::<S>(s)
-}
-
-/// Validates [IRI fragment][fragment].
-///
-/// This validator corresponds to [`RiFragmentStr`] and [`RiFragmentString`] types.
-///
-/// Note that the first `#` character in an IRI is not a part of a fragment.
-/// For example, `https://example.com/#foo` has a fragment `foo`, **not** `#foo`.
-///
-/// # Examples
-///
-/// This type can have an IRI fragment.
-/// Note that the IRI `foo://bar/baz#qux` has the fragment `qux`, **not** `#qux`.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::fragment};
-/// assert!(fragment::<UriSpec>("").is_ok());
-/// assert!(fragment::<UriSpec>("foo").is_ok());
-/// assert!(fragment::<UriSpec>("foo/bar").is_ok());
-/// assert!(fragment::<UriSpec>("/foo/bar").is_ok());
-/// assert!(fragment::<UriSpec>("//foo/bar").is_ok());
-/// assert!(fragment::<UriSpec>("https://user:pass@example.com:8080").is_ok());
-/// assert!(fragment::<UriSpec>("https://example.com/").is_ok());
-/// ```
-///
-/// Some characters and sequences cannot used in a fragment.
-///
-/// ```
-/// use iri_string::{spec::UriSpec, validate::fragment};
-/// // `<` and `>` cannot directly appear in an IRI reference.
-/// assert!(fragment::<UriSpec>("<not allowed>").is_err());
-/// // Broken percent encoding cannot appear in an IRI reference.
-/// assert!(fragment::<UriSpec>("%").is_err());
-/// assert!(fragment::<UriSpec>("%GG").is_err());
-/// // Hash sign `#` cannot appear in an IRI fragment.
-/// assert!(fragment::<UriSpec>("#hash").is_err());
-/// ```
-///
-/// [fragment]: https://tools.ietf.org/html/rfc3986#section-3.5
-/// [`RiFragmentStr`]: ../types/struct.RiFragmentStr.html
-/// [`RiFragmentString`]: ../types/struct.RiFragmentString.html
-pub fn fragment<S: Spec>(s: &str) -> Result<(), Error> {
- parser::validate_fragment::<S>(s)
-}