//! 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::("https://user:pass@example.com:8080").is_ok()); /// assert!(iri::("https://example.com/").is_ok()); /// assert!(iri::("https://example.com/foo?bar=baz").is_ok()); /// assert!(iri::("https://example.com/foo?bar=baz#qux").is_ok()); /// assert!(iri::("foo:bar").is_ok()); /// assert!(iri::("foo:").is_ok()); /// // `foo://.../` below are all allowed. See the crate documentation for detail. /// assert!(iri::("foo:/").is_ok()); /// assert!(iri::("foo://").is_ok()); /// assert!(iri::("foo:///").is_ok()); /// assert!(iri::("foo:////").is_ok()); /// assert!(iri::("foo://///").is_ok()); /// ``` /// /// Relative IRI reference is not allowed. /// /// ``` /// use iri_string::{spec::UriSpec, validate::iri}; /// // This is relative path. /// assert!(iri::("foo/bar").is_err()); /// // `/foo/bar` is an absolute path, but it is authority-relative. /// assert!(iri::("/foo/bar").is_err()); /// // `//foo/bar` is termed "network-path reference", /// // or usually called "protocol-relative reference". /// assert!(iri::("//foo/bar").is_err()); /// // Same-document reference is relative. /// assert!(iri::("#foo").is_err()); /// // Empty string is not a valid absolute IRI. /// assert!(iri::("").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::("").is_err()); /// // Broken percent encoding cannot appear in an IRI. /// assert!(iri::("%").is_err()); /// assert!(iri::("%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: &str) -> Result<(), Error> { parser::validate_uri::(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::("https://user:pass@example.com:8080").is_ok()); /// assert!(iri_reference::("https://example.com/").is_ok()); /// assert!(iri_reference::("https://example.com/foo?bar=baz").is_ok()); /// assert!(iri_reference::("https://example.com/foo?bar=baz#qux").is_ok()); /// assert!(iri_reference::("foo:bar").is_ok()); /// assert!(iri_reference::("foo:").is_ok()); /// // `foo://.../` below are all allowed. See the crate documentation for detail. /// assert!(iri_reference::("foo:/").is_ok()); /// assert!(iri_reference::("foo://").is_ok()); /// assert!(iri_reference::("foo:///").is_ok()); /// assert!(iri_reference::("foo:////").is_ok()); /// assert!(iri_reference::("foo://///").is_ok()); /// assert!(iri_reference::("foo/bar").is_ok()); /// assert!(iri_reference::("/foo/bar").is_ok()); /// assert!(iri_reference::("//foo/bar").is_ok()); /// assert!(iri_reference::("#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::("").is_err()); /// // Broken percent encoding cannot appear in an IRI reference. /// assert!(iri_reference::("%").is_err()); /// assert!(iri_reference::("%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: &str) -> Result<(), Error> { parser::validate_uri_reference::(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::("https://example.com/foo?bar=baz").is_ok()); /// assert!(absolute_iri::("foo:bar").is_ok()); /// // Scheme `foo` and empty path. /// assert!(absolute_iri::("foo:").is_ok()); /// // `foo://.../` below are all allowed. See the crate documentation for detail. /// assert!(absolute_iri::("foo:/").is_ok()); /// assert!(absolute_iri::("foo://").is_ok()); /// assert!(absolute_iri::("foo:///").is_ok()); /// assert!(absolute_iri::("foo:////").is_ok()); /// assert!(absolute_iri::("foo://///").is_ok()); /// /// ``` /// /// Relative IRI is not allowed. /// /// ``` /// use iri_string::{spec::UriSpec, validate::absolute_iri}; /// // This is relative path. /// assert!(absolute_iri::("foo/bar").is_err()); /// // `/foo/bar` is an absolute path, but it is authority-relative. /// assert!(absolute_iri::("/foo/bar").is_err()); /// // `//foo/bar` is termed "network-path reference", /// // or usually called "protocol-relative reference". /// assert!(absolute_iri::("//foo/bar").is_err()); /// // Empty string is not a valid absolute IRI. /// assert!(absolute_iri::("").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::("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::("").is_err()); /// // Broken percent encoding cannot appear in an absolute IRI. /// assert!(absolute_iri::("%").is_err()); /// assert!(absolute_iri::("%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: &str) -> Result<(), Error> { parser::validate_absolute_uri::(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::("foo").is_ok()); /// assert!(relative_ref::("foo/bar").is_ok()); /// assert!(relative_ref::("/foo").is_ok()); /// assert!(relative_ref::("//foo/bar").is_ok()); /// assert!(relative_ref::("?foo").is_ok()); /// assert!(relative_ref::("#foo").is_ok()); /// assert!(relative_ref::("foo/bar?baz#qux").is_ok()); /// // The first path component can have colon if the path is absolute. /// assert!(relative_ref::("/foo:bar/").is_ok()); /// // Second or following path components can have colon. /// assert!(relative_ref::("foo/bar://baz/").is_ok()); /// assert!(relative_ref::("./foo://bar").is_ok()); /// ``` /// /// Absolute form of a reference is not allowed. /// /// ``` /// use iri_string::{spec::UriSpec, validate::relative_ref}; /// assert!(relative_ref::("https://example.com/").is_err()); /// // The first path component cannot have colon, if the path is not absolute. /// assert!(relative_ref::("foo:bar").is_err()); /// assert!(relative_ref::("foo:").is_err()); /// assert!(relative_ref::("foo:/").is_err()); /// assert!(relative_ref::("foo://").is_err()); /// assert!(relative_ref::("foo:///").is_err()); /// assert!(relative_ref::("foo:////").is_err()); /// assert!(relative_ref::("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::("").is_err()); /// // Broken percent encoding cannot appear in a relative IRI reference. /// assert!(relative_ref::("%").is_err()); /// assert!(relative_ref::("%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: &str) -> Result<(), Error> { parser::validate_relative_ref::(s) } /// Validates [IRI path][path]. /// /// [path]: https://tools.ietf.org/html/rfc3986#section-3.3 pub fn path(s: &str) -> Result<(), Error> { parser::validate_path::(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::("").is_ok()); /// assert!(query::("foo").is_ok()); /// assert!(query::("foo/bar").is_ok()); /// assert!(query::("/foo/bar").is_ok()); /// assert!(query::("//foo/bar").is_ok()); /// assert!(query::("https://user:pass@example.com:8080").is_ok()); /// assert!(query::("https://example.com/").is_ok()); /// // Question sign `?` can appear in an IRI query. /// assert!(query::("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::("").is_err()); /// // Broken percent encoding cannot appear in an IRI reference. /// assert!(query::("%").is_err()); /// assert!(query::("%GG").is_err()); /// // Hash sign `#` cannot appear in an IRI query. /// assert!(query::("#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: &str) -> Result<(), Error> { parser::validate_query::(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::("").is_ok()); /// assert!(fragment::("foo").is_ok()); /// assert!(fragment::("foo/bar").is_ok()); /// assert!(fragment::("/foo/bar").is_ok()); /// assert!(fragment::("//foo/bar").is_ok()); /// assert!(fragment::("https://user:pass@example.com:8080").is_ok()); /// assert!(fragment::("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::("").is_err()); /// // Broken percent encoding cannot appear in an IRI reference. /// assert!(fragment::("%").is_err()); /// assert!(fragment::("%GG").is_err()); /// // Hash sign `#` cannot appear in an IRI fragment. /// assert!(fragment::("#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: &str) -> Result<(), Error> { parser::validate_fragment::(s) }