use std::str::FromStr;
use std::fmt::{self, Display};
fn check_slice_validity(slice: &str) -> bool {
slice.bytes().all(|c|
c == b'\x21' || (c >= b'\x23' && c <= b'\x7e') | (c >= b'\x80' && c <= b'\xff'))
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EntityTag {
pub weak: bool,
tag: String
}
impl EntityTag {
pub fn new(weak: bool, tag: String) -> EntityTag {
match check_slice_validity(&tag) {
true => EntityTag { weak: weak, tag: tag },
false => panic!("Invalid tag: {:?}", tag),
}
}
pub fn tag(&self) -> &str {
self.tag.as_ref()
}
pub fn set_tag(&mut self, tag: String) {
match check_slice_validity(&tag[..]) {
true => self.tag = tag,
false => panic!("Invalid tag: {:?}", tag),
}
}
pub fn strong_eq(&self, other: &EntityTag) -> bool {
self.weak == false && other.weak == false && self.tag == other.tag
}
pub fn weak_eq(&self, other: &EntityTag) -> bool {
self.tag == other.tag
}
pub fn strong_ne(&self, other: &EntityTag) -> bool {
!self.strong_eq(other)
}
pub fn weak_ne(&self, other: &EntityTag) -> bool {
!self.weak_eq(other)
}
}
impl Display for EntityTag {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.weak {
true => write!(f, "W/\"{}\"", self.tag),
false => write!(f, "\"{}\"", self.tag),
}
}
}
impl FromStr for EntityTag {
type Err = ::Error;
fn from_str(s: &str) -> ::Result<EntityTag> {
let length: usize = s.len();
let slice = &s[..];
if !slice.ends_with('"') {
return Err(::Error::Header);
}
if slice.starts_with('"') && check_slice_validity(&slice[1..length-1]) {
return Ok(EntityTag { weak: false, tag: slice[1..length-1].to_owned() });
} else if slice.starts_with("W/\"") && check_slice_validity(&slice[3..length-1]) {
return Ok(EntityTag { weak: true, tag: slice[3..length-1].to_owned() });
}
Err(::Error::Header)
}
}
#[cfg(test)]
mod tests {
use super::EntityTag;
#[test]
fn test_etag_parse_success() {
assert_eq!("\"foobar\"".parse::<EntityTag>().unwrap(), EntityTag::new(false, "foobar".to_owned()));
assert_eq!("\"\"".parse::<EntityTag>().unwrap(), EntityTag::new(false, "".to_owned()));
assert_eq!("W/\"weaktag\"".parse::<EntityTag>().unwrap(), EntityTag::new(true, "weaktag".to_owned()));
assert_eq!("W/\"\x65\x62\"".parse::<EntityTag>().unwrap(), EntityTag::new(true, "\x65\x62".to_owned()));
assert_eq!("W/\"\"".parse::<EntityTag>().unwrap(), EntityTag::new(true, "".to_owned()));
}
#[test]
fn test_etag_parse_failures() {
assert!("no-dquotes".parse::<EntityTag>().is_err());
assert!("w/\"the-first-w-is-case-sensitive\"".parse::<EntityTag>().is_err());
assert!("".parse::<EntityTag>().is_err());
assert!("\"unmatched-dquotes1".parse::<EntityTag>().is_err());
assert!("unmatched-dquotes2\"".parse::<EntityTag>().is_err());
assert!("matched-\"dquotes\"".parse::<EntityTag>().is_err());
}
#[test]
fn test_etag_fmt() {
assert_eq!(format!("{}", EntityTag::new(false, "foobar".to_owned())), "\"foobar\"");
assert_eq!(format!("{}", EntityTag::new(false, "".to_owned())), "\"\"");
assert_eq!(format!("{}", EntityTag::new(true, "weak-etag".to_owned())), "W/\"weak-etag\"");
assert_eq!(format!("{}", EntityTag::new(true, "\u{0065}".to_owned())), "W/\"\x65\"");
assert_eq!(format!("{}", EntityTag::new(true, "".to_owned())), "W/\"\"");
}
#[test]
fn test_cmp() {
let mut etag1 = EntityTag::new(true, "1".to_owned());
let mut etag2 = EntityTag::new(true, "1".to_owned());
assert_eq!(etag1.strong_eq(&etag2), false);
assert_eq!(etag1.weak_eq(&etag2), true);
assert_eq!(etag1.strong_ne(&etag2), true);
assert_eq!(etag1.weak_ne(&etag2), false);
etag1 = EntityTag::new(true, "1".to_owned());
etag2 = EntityTag::new(true, "2".to_owned());
assert_eq!(etag1.strong_eq(&etag2), false);
assert_eq!(etag1.weak_eq(&etag2), false);
assert_eq!(etag1.strong_ne(&etag2), true);
assert_eq!(etag1.weak_ne(&etag2), true);
etag1 = EntityTag::new(true, "1".to_owned());
etag2 = EntityTag::new(false, "1".to_owned());
assert_eq!(etag1.strong_eq(&etag2), false);
assert_eq!(etag1.weak_eq(&etag2), true);
assert_eq!(etag1.strong_ne(&etag2), true);
assert_eq!(etag1.weak_ne(&etag2), false);
etag1 = EntityTag::new(false, "1".to_owned());
etag2 = EntityTag::new(false, "1".to_owned());
assert_eq!(etag1.strong_eq(&etag2), true);
assert_eq!(etag1.weak_eq(&etag2), true);
assert_eq!(etag1.strong_ne(&etag2), false);
assert_eq!(etag1.weak_ne(&etag2), false);
}
}