#![allow(dead_code)]
use core::fmt;
use RawKind::*;
#[derive(Clone, Copy, PartialEq, Eq)]
enum RawKind {
Invalid,
Iri,
IriAbsolute,
IriRelative,
Uri,
UriAbsolute,
UriRelative,
}
impl RawKind {
fn spec_is(self, spec: Spec) -> bool {
match spec {
Spec::Uri => matches!(self, Self::Uri | Self::UriAbsolute | Self::UriRelative),
Spec::Iri => self != Self::Invalid,
}
}
fn kind_is(self, kind: Kind) -> bool {
match kind {
Kind::Absolute => matches!(self, Self::UriAbsolute | Self::IriAbsolute),
Kind::Normal => matches!(
self,
Self::UriAbsolute | Self::Uri | Self::IriAbsolute | Self::Iri
),
Kind::Reference => self != Self::Invalid,
Kind::Relative => matches!(self, Self::UriRelative | Self::IriRelative),
}
}
fn is(self, spec: Spec, kind: Kind) -> bool {
self.spec_is(spec) && self.kind_is(kind)
}
}
const STRINGS: &[(RawKind, &str)] = &[
(UriAbsolute, "https://user:pass@example.com:8080"),
(UriAbsolute, "https://example.com/"),
(UriAbsolute, "https://example.com/foo?bar=baz"),
(Uri, "https://example.com/foo?bar=baz#qux"),
(UriAbsolute, "foo:bar"),
(UriAbsolute, "foo:"),
(UriAbsolute, "foo:/"),
(UriAbsolute, "foo://"),
(UriAbsolute, "foo:///"),
(UriAbsolute, "foo:////"),
(UriAbsolute, "foo://///"),
(UriRelative, "foo"),
(UriRelative, "foo/bar"),
(UriRelative, "foo//bar"),
(UriRelative, "/"),
(UriRelative, "/foo"),
(UriRelative, "/foo/bar"),
(UriRelative, "//foo/bar"),
(UriRelative, "/foo//bar"),
(UriRelative, "?"),
(UriRelative, "???"),
(UriRelative, "?foo"),
(UriRelative, "#"),
(UriRelative, "#foo"),
(Invalid, "##"),
(Invalid, "fragment#cannot#have#hash#char"),
(Invalid, "<"),
(Invalid, ">"),
(Invalid, "lt<and-gt>not-allowed"),
(Invalid, "%"),
(Invalid, "%0"),
(Invalid, "%f"),
(Invalid, "%F"),
(Invalid, "%0g"),
(Invalid, "%0G"),
(Invalid, "%GG"),
(Invalid, "%G0"),
];
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Spec {
Uri,
Iri,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Kind {
Absolute,
Normal,
Reference,
Relative,
}
pub fn positive(spec: Spec, kind: Kind) -> impl Iterator<Item = &'static str> {
STRINGS
.iter()
.filter(move |(raw_kind, _)| raw_kind.is(spec, kind))
.map(|(_, s)| *s)
}
pub fn negative(spec: Spec, kind: Kind) -> impl Iterator<Item = &'static str> {
STRINGS
.iter()
.filter(move |(raw_kind, _)| !raw_kind.is(spec, kind))
.map(|(_, s)| *s)
}
pub(crate) fn eq_display_str<T>(d: &T, s: &str) -> bool
where
T: ?Sized + fmt::Display,
{
use core::fmt::Write as _;
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()
}
#[allow(unused_macros)]
macro_rules! assert_eq_display {
($left:expr, $right:expr $(,)?) => {{
match (&$left, &$right) {
(left, right) => {
assert!(
utils::eq_display_str(left, right.as_ref()),
"`eq_str_display(left, right)`\n left: `{left}`,\n right: `{right}`",
);
#[cfg(feature = "alloc")]
{
let left = left.to_string();
let right = right.to_string();
assert_eq!(left, right);
}
}
}
}};
($left:expr, $right:expr, $($args:tt)*) => {{
match (&$left, &$right) {
(left, right) => {
assert!(
utils::eq_display_str(left, right.as_ref()),
"{}",
format_args!(
"{}: {}",
format_args!(
"`eq_str_display(left, right)`\n left: `{left}`,\n right: `{right}`",
),
format_args!($($args)*)
)
);
#[cfg(feature = "alloc")]
{
let left = left.to_string();
let right = right.to_string();
assert_eq!(left, right, $($args)*);
}
}
}
}};
}