use std::str::FromStr;
use std::borrow::Cow;
use std::num::NonZero;
use std::fmt::{self, Formatter};
use regex::{Match, Captures};
use crate::{RegexPattern, FromMatch, ErasedLifetime, Error};
impl<'h> FromMatch<'h> for &'h str {
fn from_match(_name: &'static str, m: Match<'h>, _captures: &Captures<'h>) -> Result<Self, Error> {
Ok(m.as_str())
}
}
impl<'h> FromMatch<'h> for &'h [u8] {
fn from_match(_name: &'static str, m: Match<'h>, _captures: &Captures<'h>) -> Result<Self, Error> {
Ok(m.as_str().as_bytes())
}
}
impl<'h> FromMatch<'h> for Vec<u8> {
fn from_match(_name: &'static str, m: Match<'h>, _captures: &Captures<'h>) -> Result<Self, Error> {
Ok(m.as_str().as_bytes().to_vec())
}
}
impl<'h, T> FromMatch<'h> for Option<T>
where
T: FromMatch<'h>
{
fn from_match(name: &'static str, m: Match<'h>, captures: &Captures<'h>) -> Result<Self, Error> {
if m.is_empty() {
Ok(None)
} else {
T::from_match(name, m, captures).map(Some)
}
}
}
impl<'h, T> FromMatch<'h> for Cow<'h, T>
where
T: ?Sized + ToOwned,
&'h T: FromMatch<'h>,
{
fn from_match(name: &'static str, m: Match<'h>, captures: &Captures<'h>) -> Result<Self, Error> {
<&T>::from_match(name, m, captures).map(Cow::Borrowed)
}
}
impl<'h, T> FromMatch<'h> for Box<T>
where
T: FromMatch<'h>,
{
fn from_match(name: &'static str, m: Match<'h>, captures: &Captures<'h>) -> Result<Self, Error> {
T::from_match(name, m, captures).map(Box::new)
}
}
impl<'h> FromMatch<'h> for &'h std::path::Path {
fn from_match(_name: &'static str, m: Match<'h>, _captures: &Captures<'h>) -> Result<Self, Error> {
Ok(std::path::Path::new(m.as_str()))
}
}
impl<'h> FromMatch<'h> for &'h std::ffi::OsStr {
fn from_match(_name: &'static str, m: Match<'h>, _captures: &Captures<'h>) -> Result<Self, Error> {
Ok(std::ffi::OsStr::new(m.as_str()))
}
}
impl<'h> FromMatch<'h> for &'h std::ffi::CStr {
fn from_match(name: &'static str, m: Match<'h>, _captures: &Captures<'h>) -> Result<Self, Error> {
std::ffi::CStr::from_bytes_with_nul(m.as_str().as_bytes()).map_err(|error| {
Error::group_from_str(name, m.range(), error)
})
}
}
macro_rules! impl_from_match_for_from_str {
($($ty:ty)+) => {$(
impl<'h> FromMatch<'h> for $ty {
fn from_match(name: &'static str, m: Match<'h>, _captures: &Captures<'h>) -> Result<Self, Error> {
Self::from_str(m.as_str()).map_err(|error| {
Error::group_from_str(name, m.range(), error)
})
}
}
)+}
}
impl_from_match_for_from_str! {
bool char
u8 u16 u32 u64 u128 usize
i8 i16 i32 i64 i128 isize
NonZero<u8> NonZero<u16> NonZero<u32> NonZero<u64> NonZero<u128> NonZero<usize>
NonZero<i8> NonZero<i16> NonZero<i32> NonZero<i64> NonZero<i128> NonZero<isize>
f32 f64
String
std::ffi::OsString
std::ffi::CString
std::path::PathBuf
std::net::IpAddr
std::net::Ipv4Addr
std::net::Ipv6Addr
std::net::SocketAddr
std::net::SocketAddrV4
std::net::SocketAddrV6
}
impl FromMatch<'_> for Box<str> {
fn from_match(_name: &'static str, m: Match<'_>, _captures: &Captures<'_>) -> Result<Self, Error> {
Ok(m.as_str().into())
}
}
impl FromMatch<'_> for Box<std::path::Path> {
fn from_match(_name: &'static str, m: Match<'_>, _captures: &Captures<'_>) -> Result<Self, Error> {
Ok(std::path::Path::new(m.as_str()).into())
}
}
impl FromMatch<'_> for Box<std::ffi::OsStr> {
fn from_match(_name: &'static str, m: Match<'_>, _captures: &Captures<'_>) -> Result<Self, Error> {
Ok(std::ffi::OsStr::new(m.as_str()).into())
}
}
impl FromMatch<'_> for Box<std::ffi::CStr> {
fn from_match(name: &'static str, m: Match<'_>, _captures: &Captures<'_>) -> Result<Self, Error> {
std::ffi::CStr::from_bytes_with_nul(m.as_str().as_bytes())
.map(Box::from)
.map_err(|error| Error::group_from_str(name, m.range(), error))
}
}
impl<T: ?Sized + RegexPattern> RegexPattern for &T {
fn fmt_pattern(f: &mut Formatter<'_>) -> fmt::Result {
T::fmt_pattern(f)
}
}
impl<T: ?Sized + RegexPattern> RegexPattern for &mut T {
fn fmt_pattern(f: &mut Formatter<'_>) -> fmt::Result {
T::fmt_pattern(f)
}
}
impl<T: ?Sized + RegexPattern> RegexPattern for Box<T> {
fn fmt_pattern(f: &mut Formatter<'_>) -> fmt::Result {
T::fmt_pattern(f)
}
}
impl<T: ?Sized + ToOwned + RegexPattern> RegexPattern for Cow<'_, T> {
fn fmt_pattern(f: &mut Formatter<'_>) -> fmt::Result {
T::fmt_pattern(f)
}
}
impl<T: RegexPattern> RegexPattern for Option<T> {
fn fmt_pattern(f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "(?:{})?", T::pattern_display())
}
}
macro_rules! impl_regex_pattern {
($($($ty:ty),+ => $pat:expr;)+) => {$(
$(
impl RegexPattern for $ty {
fn fmt_pattern(f: &mut Formatter<'_>) -> fmt::Result {
f.write_str($pat)
}
}
)+
)+}
}
macro_rules! ipv4_byte_decimal {
() => { "0|1[0-9]{0,2}|2[0-4][0-9]|25[0-5]|2[0-9]?|[3-9][0-9]?" }
}
macro_rules! ipv4_address_pattern {
() => { concat!("(?:(?:", ipv4_byte_decimal!(), r")\.){3}(?:", ipv4_byte_decimal!(), ")") }
}
macro_rules! ipv6_address_pattern {
() => { "[0-9a-fA-F:]{2,39}" } }
impl_regex_pattern! {
bool => "false|true";
u8, u16, u32, u64, u128, usize => r"\+?[0-9]+";
i8, i16, i32, i64, i128, isize => r"[-\+]?[0-9]+";
NonZero<u8>, NonZero<u16>, NonZero<u32>, NonZero<u64>, NonZero<u128>, NonZero<usize> => r"\+?[1-9][0-9]*";
NonZero<i8>, NonZero<i16>, NonZero<i32>, NonZero<i64>, NonZero<i128>, NonZero<isize> => r"[-\+]?[1-9][0-9]*";
f32, f64 => r"[-\+]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)";
char => ".";
str, String => ".*";
std::ffi::OsStr, std::ffi::OsString, std::ffi::CStr, std::ffi::CString => ".*";
std::path::Path, std::path::PathBuf => ".*";
std::net::Ipv4Addr => ipv4_address_pattern!();
std::net::Ipv6Addr => ipv6_address_pattern!();
std::net::IpAddr => concat!("(?:", ipv4_address_pattern!(), ")|(?:", ipv6_address_pattern!(), ")");
std::net::SocketAddrV4 => concat!(ipv4_address_pattern!(), ":[0-9]+");
std::net::SocketAddrV6 => concat!(r"\[", ipv6_address_pattern!(), r"(?:%[0-9]+)?\]:[0-9]+");
std::net::SocketAddr => concat!("(?:(?:", ipv4_address_pattern!(), r")|(?:\[", ipv6_address_pattern!(), r"(?:%[0-9]+)?\])):[0-9]+");
}
macro_rules! impl_erased_lifetime_self {
($($ty:ty)+) => {$(
impl ErasedLifetime for $ty {
type Erased = Self;
}
)+}
}
impl_erased_lifetime_self!{
bool char
u8 u16 u32 u64 u128 usize
i8 i16 i32 i64 i128 isize
NonZero<u8> NonZero<u16> NonZero<u32> NonZero<u64> NonZero<u128> NonZero<usize>
NonZero<i8> NonZero<i16> NonZero<i32> NonZero<i64> NonZero<i128> NonZero<isize>
f32 f64
str String
std::ffi::OsStr std::ffi::OsString
std::ffi::CStr std::ffi::CString
std::path::Path std::path::PathBuf
std::net::IpAddr std::net::Ipv4Addr std::net::Ipv6Addr
std::net::SocketAddr std::net::SocketAddrV4 std::net::SocketAddrV6
}
impl<T> ErasedLifetime for &T
where
T: ?Sized + ErasedLifetime
{
type Erased = &'static T::Erased;
}
impl<T> ErasedLifetime for &mut T
where
T: ?Sized + ErasedLifetime
{
type Erased = &'static mut T::Erased;
}
impl<T> ErasedLifetime for Box<T>
where
T: ?Sized + ErasedLifetime
{
type Erased = Box<T::Erased>;
}
impl<T> ErasedLifetime for Option<T>
where
T: ErasedLifetime,
T::Erased: Sized,
{
type Erased = Option<T::Erased>;
}
impl<T> ErasedLifetime for Cow<'_, T>
where
T: ?Sized + ToOwned + ErasedLifetime,
T::Erased: ToOwned,
{
type Erased = Cow<'static, T::Erased>;
}
impl ErasedLifetime for () {
type Erased = Self;
}
macro_rules! impl_erased_lifetime_tuple {
($tail:ident, $($head:ident),+) => {
impl<$tail, $($head,)+> ErasedLifetime for ($($head,)+ $tail)
where
$(
$head: ErasedLifetime,
$head::Erased: Sized,
)*
$tail: ?Sized + ErasedLifetime, {
type Erased = ($($head::Erased,)+ $tail::Erased);
}
impl_erased_lifetime_tuple!($($head),+);
};
($ty:ident) => {
impl<$ty: ?Sized + ErasedLifetime> ErasedLifetime for ($ty,) {
type Erased = ($ty::Erased,);
}
};
}
impl_erased_lifetime_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);