From 20a585e30bbb060a91839de7e95fd75a95d03d93 Mon Sep 17 00:00:00 2001 From: Hugo Duncan Date: Sat, 7 Feb 2015 12:48:26 -0500 Subject: [PATCH] feat(headers): add AcceptLanguage header Adds header support for Accept-Language, using a struct for the primary and sub components of the language. --- src/header/common/accept_language.rs | 86 ++++++++++++++++++++++++++++ src/header/common/mod.rs | 2 + 2 files changed, 88 insertions(+) create mode 100644 src/header/common/accept_language.rs diff --git a/src/header/common/accept_language.rs b/src/header/common/accept_language.rs new file mode 100644 index 0000000000..d1f337c45d --- /dev/null +++ b/src/header/common/accept_language.rs @@ -0,0 +1,86 @@ +use header::{self, QualityItem}; +use std::str::FromStr; +use std::fmt; + +/// A language tag. +/// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.10 +#[derive(Clone, PartialEq, Debug)] +pub struct Language{ + primary: String, + sub: Option +} + +impl FromStr for Language { + type Err = (); + fn from_str(s: &str) -> Result { + let mut i = s.split_str("-"); + let p = i.next(); + let s = i.next(); + match (p, s) { + (Some(p),Some(s)) => Ok(Language{primary: p.to_string(), + sub: Some(s.to_string())}), + (Some(p),_) => Ok(Language{primary: p.to_string(), sub: None}), + _ => Err(()) + } + } +} + +impl fmt::Display for Language { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "{}", self.primary)); + match self.sub { + Some(ref s) => write!(f, "-{}", s), + None => Ok(()) + } + } +} + +/// The `Accept-Language` header +/// +/// The `Accept-Language` header can be used by clients to indicate what +/// response languages they accept. +#[derive(Clone, PartialEq, Debug)] +pub struct AcceptLanguage(pub Vec>); + +impl_list_header!(AcceptLanguage, + "Accept-Language", + Vec>); + +bench_header!(bench, AcceptLanguage, + { vec![b"en-us;q=1.0, en;q=0.5, fr".to_vec()] }); + +#[test] +fn test_parse_header() { + let a: AcceptLanguage = header::Header::parse_header( + [b"en-us;q=1.0, en;q=0.5, fr".to_vec()].as_slice()).unwrap(); + let b = AcceptLanguage(vec![ + QualityItem { item: Language{primary: "en".to_string(), + sub: Some("us".to_string())}, + quality: 1f32 }, + QualityItem { item: Language{primary: "en".to_string(), sub: None}, + quality: 0.5f32 }, + QualityItem { item: Language{primary: "fr".to_string(), sub: None}, + quality: 1f32 }, + ]); + assert_eq!(format!("{}", a), format!("{}", b)); + assert_eq!(a, b); +} + +#[test] +fn test_display() { + assert_eq!("en".to_string(), + format!("{}", Language{primary: "en".to_string(), + sub: None})); + assert_eq!("en-us".to_string(), + format!("{}", Language{primary: "en".to_string(), + sub: Some("us".to_string())})); +} + +#[test] +fn test_from_str() { + assert_eq!(Language { primary: "en".to_string(), sub: None }, + "en".parse().unwrap()); + assert_eq!(Language { primary: "en".to_string(), + sub: Some("us".to_string()) }, + "en-us".parse().unwrap()); +} diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 01dc723929..5363d8b96c 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -9,6 +9,7 @@ pub use self::access_control::*; pub use self::accept::Accept; pub use self::accept_encoding::AcceptEncoding; +pub use self::accept_language::AcceptLanguage; pub use self::allow::Allow; pub use self::authorization::{Authorization, Scheme, Basic}; pub use self::cache_control::{CacheControl, CacheDirective}; @@ -147,6 +148,7 @@ macro_rules! impl_header( mod access_control; mod accept; mod accept_encoding; +mod accept_language; mod allow; mod authorization; mod cache_control;