use serde::{Deserialize, Deserializer};
#[derive(Debug, Clone, PartialEq)]
pub enum Method {
Get,
Post,
Put,
Delete,
}
impl<'de> Deserialize<'de> for Method {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?.to_uppercase();
match s.as_str() {
"GET" => Ok(Method::Get),
"POST" => Ok(Method::Post),
"PUT" => Ok(Method::Put),
"DELETE" => Ok(Method::Delete),
_ => Err(serde::de::Error::custom(format!("Invalid method: {}", s))),
}
}
}
impl Method {
pub fn to_string(&self) -> String {
match self {
Method::Get => "GET".to_string(),
Method::Post => "POST".to_string(),
Method::Put => "PUT".to_string(),
Method::Delete => "DELETE".to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Urn {
pub method: Method,
pub url: String,
}
impl<'de> Deserialize<'de> for Urn {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(Urn::new(s))
}
}
impl Urn {
pub fn new(urn: String) -> Self {
if urn.starts_with("http:") || urn.starts_with("https:") {
return Self {
method: Method::Get,
url: urn,
};
}
let parts: Vec<&str> = urn.splitn(2, ':').collect();
let method = parts[0].trim();
let url = parts[1].trim();
if url.is_empty() {
panic!("Invalid URN: {}", urn);
}
Self {
method: match method.to_uppercase().as_str() {
"GET" => Method::Get,
"POST" => Method::Post,
"PUT" => Method::Put,
"DELETE" => Method::Delete,
_ => panic!("Invalid method: {}", method),
},
url: url.to_string(),
}
}
pub fn matches(&self, method: &str, url: &str) -> bool {
self.method.to_string() == method.to_uppercase() && url.starts_with(&self.url)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_urn_new() {
let urn = Urn::new("GET:example.com".to_string());
assert!(matches!(urn.method, Method::Get));
assert_eq!(urn.url, "example.com");
}
#[test]
fn test_urn_with_complex_url() {
let urn = Urn::new("POST:api.example.com/v1/users".to_string());
assert!(matches!(urn.method, Method::Post));
assert_eq!(urn.url, "api.example.com/v1/users");
}
#[test]
#[should_panic(expected = "Invalid URN:")]
fn test_urn_with_empty_url() {
let _urn = Urn::new("PUT:".to_string());
}
#[test]
fn test_http_prefix_urls() {
let urn = Urn::new("http:example.com".to_string());
assert!(matches!(urn.method, Method::Get));
assert_eq!(urn.url, "http:example.com");
let urn = Urn::new("https:example.com".to_string());
assert!(matches!(urn.method, Method::Get));
assert_eq!(urn.url, "https:example.com");
}
}