use std::{fmt, ops::Deref};
use crate::S3Key;
impl Deref for S3Key {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PartialEq<str> for S3Key {
fn eq(&self, other: &str) -> bool {
self.0.eq(other)
}
fn ne(&self, other: &str) -> bool {
!self.eq(other)
}
}
impl PartialEq<&str> for S3Key {
fn eq(&self, other: &&str) -> bool {
self.0.eq(other)
}
fn ne(&self, other: &&str) -> bool {
!self.eq(other)
}
}
impl fmt::Display for S3Key {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self)
}
}
impl S3Key {
pub fn empty() -> S3Key {
S3Key(String::from(""))
}
pub fn join(&self, part: &str) -> S3Key {
let suffix = if part.ends_with("/") { "/" } else { "" };
let normalized = part.trim_matches('/').to_string();
let needs_separator = !self.is_empty() && !self.ends_with("/");
let separator = if needs_separator { "/" } else { "" };
S3Key(format!("{}{}{}{}", self, separator, normalized, suffix))
}
pub fn new(key: &str) -> S3Key {
S3Key::empty().join(key)
}
}
#[cfg(test)]
mod tests {
use crate::S3Key;
#[test]
fn test_empty() {
let key = S3Key::empty();
assert_eq!(key, "");
}
#[test]
fn test_new() {
let cases = [
["clowns.jpg", "clowns.jpg"],
["/clowns.jpg", "clowns.jpg"],
["//clowns.jpg", "clowns.jpg"],
["images/", "images/"],
["images//", "images/"],
];
for case in cases {
let key = S3Key::new(case[0]);
assert_eq!(key, case[1]);
}
}
#[test]
fn test_join_chained() {
let cases = [
["images", "clowns.jpg", "images/clowns.jpg"],
["images/", "clowns.jpg", "images/clowns.jpg"],
["images", "/clowns.jpg", "images/clowns.jpg"],
["images/", "/clowns.jpg", "images/clowns.jpg"],
];
for case in cases {
let key = S3Key::new(case[0]).join(case[1]);
assert_eq!(key, case[2]);
}
}
}