use std::fmt::{Display, Formatter};
use std::str::FromStr;
use serde::Serialize;
use super::Result;
use crate::config::error::Error;
#[derive(Hash, PartialEq, Eq, Debug, Serialize, Clone)]
pub struct RouterPattern{
segments: Vec<String>,
}
impl RouterPattern {
pub fn new<S: AsRef<str> + Into<String>>(s: S) -> Result<Self> {
let segments = s.as_ref().split("/")
.filter(|s| !s.is_empty())
.map(|s| s.into())
.collect();
Ok(Self{ segments })
}
pub fn is_match<S: AsRef<str>>(&self, other: S) -> bool {
let mut other_segments = other.as_ref()
.split('/')
.filter(|s| !s.is_empty());
for s in &self.segments {
let Some(n) = other_segments.next() else {
return false;
};
if s != "*" && s != n {
return false;
}
}
true
}
pub fn rest_after_match<S: AsRef<str>>(&self, other: S) -> Option<String> {
let mut other_segments = other.as_ref()
.split('/')
.filter(|s| !s.is_empty());
for s in &self.segments {
let Some(n) = other_segments.next() else {
return None;
};
if s != "*" && s != n {
return None;
}
}
let remaining = other_segments.fold(String::from("/"), |mut acc, segment| {
if !acc.is_empty() {
acc.push('/');
}
acc.push_str(segment);
acc
});
Some(remaining)
}
}
impl From<RouterPattern> for String {
fn from(value: RouterPattern) -> Self {
format!("/{}", value.segments.join("/"))
}
}
impl Display for RouterPattern {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "/{}", self.segments.join("/"))
}
}
impl TryFrom<String> for RouterPattern {
type Error = Error;
fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
Self::new(value)
}
}
impl TryFrom<&str> for RouterPattern {
type Error = Error;
fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
Self::new(value)
}
}
impl FromStr for RouterPattern {
type Err = Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
RouterPattern::try_from(s)
}
}