use std::{borrow::Borrow, ops::Deref};
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Path(pub String);
impl<T: Into<String>> From<T> for Path {
fn from(value: T) -> Self {
Path(value.into())
}
}
impl Deref for Path {
type Target = str;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl AsRef<[u8]> for Path {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl AsRef<str> for Path {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Borrow<str> for Path {
fn borrow(&self) -> &str {
self.0.as_ref()
}
}
impl std::ops::DivAssign<Path> for Path {
fn div_assign(&mut self, rhs: Path) {
*self /= rhs.0;
}
}
impl std::ops::DivAssign<String> for Path {
fn div_assign(&mut self, rhs: String) {
if self.0.is_empty() {
self.0 = rhs;
} else {
match rhs.chars().next() {
None => (),
Some('/') => {
self.0 = rhs;
}
_ => {
match self.0.chars().last() {
None => unreachable!(),
Some('/') => (),
_ => self.0.push('/'),
}
self.0.push_str(rhs.as_ref());
}
}
}
}
}
impl<T: AsRef<str>> std::ops::DivAssign<&T> for Path {
fn div_assign(&mut self, rhs: &T) {
let rhs = rhs.as_ref();
if self.0.is_empty() {
self.0 = String::from(rhs);
} else {
match rhs.chars().next() {
None => (),
Some('/') => {
self.0 = String::from(rhs);
}
_ => {
match self.0.chars().last() {
None => unreachable!(),
Some('/') => (),
_ => self.0.push('/'),
}
self.0.push_str(rhs);
}
}
}
}
}
impl<T> std::ops::Div<T> for Path
where
Path: std::ops::DivAssign<T>,
{
type Output = Path;
fn div(mut self, rhs: T) -> Self::Output {
self /= rhs;
self
}
}
#[cfg(test)]
mod test {
use crate::message::test_utils::{encode_decode, fail_decode, BYTES_INVALID, BYTES_VALID};
use super::Path;
#[test]
fn encode_success() {
for (bytes, encoded) in BYTES_VALID {
encode_decode(Path(bytes.to_owned()), encoded);
}
}
#[test]
fn decode_failure() {
for (bytes, expected) in BYTES_INVALID {
assert_eq!(fail_decode::<Path>(bytes), expected);
}
}
#[test]
fn path_concatenation() {
assert_eq!(Path::from("abc"), Path::from("abc") / &"");
assert_eq!(Path::from("abc/"), Path::from("abc/") / &"");
assert_eq!(Path::from("def"), Path::from("") / &"def");
assert_eq!(Path::from("/def"), Path::from("/") / &"def");
assert_eq!(Path::from("abc/def"), Path::from("abc") / &"def");
assert_eq!(Path::from("abc/def"), Path::from("abc/") / &"def");
assert_eq!(Path::from("/def"), Path::from("abc") / &"/def");
assert_eq!(Path::from("/def"), Path::from("abc/") / &"/def");
assert_eq!(Path::from("abc"), Path::from("abc") / String::from(""));
assert_eq!(Path::from("abc/"), Path::from("abc/") / String::from(""));
assert_eq!(Path::from("def"), Path::from("") / String::from("def"));
assert_eq!(Path::from("/def"), Path::from("/") / String::from("def"));
assert_eq!(
Path::from("abc/def"),
Path::from("abc") / String::from("def")
);
assert_eq!(
Path::from("abc/def"),
Path::from("abc/") / String::from("def")
);
assert_eq!(Path::from("/def"), Path::from("abc") / String::from("/def"));
assert_eq!(
Path::from("/def"),
Path::from("abc/") / String::from("/def")
);
assert_eq!(Path::from("abc"), Path::from("abc") / Path::from(""));
assert_eq!(Path::from("abc/"), Path::from("abc/") / Path::from(""));
assert_eq!(Path::from("def"), Path::from("") / Path::from("def"));
assert_eq!(Path::from("/def"), Path::from("/") / Path::from("def"));
assert_eq!(Path::from("abc/def"), Path::from("abc") / Path::from("def"));
assert_eq!(
Path::from("abc/def"),
Path::from("abc/") / Path::from("def")
);
assert_eq!(Path::from("/def"), Path::from("abc") / Path::from("/def"));
assert_eq!(Path::from("/def"), Path::from("abc/") / Path::from("/def"));
}
}