#![cfg(feature = "serde")] extern crate serde; use self::serde::de::{ Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, Unexpected, VariantAccess, Visitor, }; use self::serde::ser::{Serialize, Serializer}; use {Level, LevelFilter, LOG_LEVEL_NAMES}; use std::fmt; use std::str::{self, FromStr}; // The Deserialize impls are handwritten to be case insensitive using FromStr. impl Serialize for Level { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match *self { Level::Error => serializer.serialize_unit_variant("Level", 0, "ERROR"), Level::Warn => serializer.serialize_unit_variant("Level", 1, "WARN"), Level::Info => serializer.serialize_unit_variant("Level", 2, "INFO"), Level::Debug => serializer.serialize_unit_variant("Level", 3, "DEBUG"), Level::Trace => serializer.serialize_unit_variant("Level", 4, "TRACE"), } } } impl<'de> Deserialize<'de> for Level { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct LevelIdentifier; impl<'de> Visitor<'de> for LevelIdentifier { type Value = Level; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("log level") } fn visit_str(self, s: &str) -> Result where E: Error, { // Case insensitive. FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES[1..])) } fn visit_bytes(self, value: &[u8]) -> Result where E: Error, { let variant = str::from_utf8(value) .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; self.visit_str(variant) } fn visit_u64(self, v: u64) -> Result where E: Error, { let variant = LOG_LEVEL_NAMES[1..] .get(v as usize) .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?; self.visit_str(variant) } } impl<'de> DeserializeSeed<'de> for LevelIdentifier { type Value = Level; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_identifier(LevelIdentifier) } } struct LevelEnum; impl<'de> Visitor<'de> for LevelEnum { type Value = Level; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("log level") } fn visit_enum(self, value: A) -> Result where A: EnumAccess<'de>, { let (level, variant) = value.variant_seed(LevelIdentifier)?; // Every variant is a unit variant. variant.unit_variant()?; Ok(level) } } deserializer.deserialize_enum("Level", &LOG_LEVEL_NAMES[1..], LevelEnum) } } impl Serialize for LevelFilter { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match *self { LevelFilter::Off => serializer.serialize_unit_variant("LevelFilter", 0, "OFF"), LevelFilter::Error => serializer.serialize_unit_variant("LevelFilter", 1, "ERROR"), LevelFilter::Warn => serializer.serialize_unit_variant("LevelFilter", 2, "WARN"), LevelFilter::Info => serializer.serialize_unit_variant("LevelFilter", 3, "INFO"), LevelFilter::Debug => serializer.serialize_unit_variant("LevelFilter", 4, "DEBUG"), LevelFilter::Trace => serializer.serialize_unit_variant("LevelFilter", 5, "TRACE"), } } } impl<'de> Deserialize<'de> for LevelFilter { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct LevelFilterIdentifier; impl<'de> Visitor<'de> for LevelFilterIdentifier { type Value = LevelFilter; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("log level filter") } fn visit_str(self, s: &str) -> Result where E: Error, { // Case insensitive. FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES)) } fn visit_bytes(self, value: &[u8]) -> Result where E: Error, { let variant = str::from_utf8(value) .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?; self.visit_str(variant) } fn visit_u64(self, v: u64) -> Result where E: Error, { let variant = LOG_LEVEL_NAMES .get(v as usize) .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?; self.visit_str(variant) } } impl<'de> DeserializeSeed<'de> for LevelFilterIdentifier { type Value = LevelFilter; fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_identifier(LevelFilterIdentifier) } } struct LevelFilterEnum; impl<'de> Visitor<'de> for LevelFilterEnum { type Value = LevelFilter; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("log level filter") } fn visit_enum(self, value: A) -> Result where A: EnumAccess<'de>, { let (level_filter, variant) = value.variant_seed(LevelFilterIdentifier)?; // Every variant is a unit variant. variant.unit_variant()?; Ok(level_filter) } } deserializer.deserialize_enum("LevelFilter", &LOG_LEVEL_NAMES, LevelFilterEnum) } } #[cfg(test)] mod tests { extern crate serde_test; use self::serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token}; use {Level, LevelFilter}; fn level_token(variant: &'static str) -> Token { Token::UnitVariant { name: "Level", variant: variant, } } fn level_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { [ Token::Enum { name: "Level" }, Token::Bytes(variant), Token::Unit, ] } fn level_variant_tokens(variant: u32) -> [Token; 3] { [ Token::Enum { name: "Level" }, Token::U32(variant), Token::Unit, ] } fn level_filter_token(variant: &'static str) -> Token { Token::UnitVariant { name: "LevelFilter", variant: variant, } } fn level_filter_bytes_tokens(variant: &'static [u8]) -> [Token; 3] { [ Token::Enum { name: "LevelFilter", }, Token::Bytes(variant), Token::Unit, ] } fn level_filter_variant_tokens(variant: u32) -> [Token; 3] { [ Token::Enum { name: "LevelFilter", }, Token::U32(variant), Token::Unit, ] } #[test] fn test_level_ser_de() { let cases = [ (Level::Error, [level_token("ERROR")]), (Level::Warn, [level_token("WARN")]), (Level::Info, [level_token("INFO")]), (Level::Debug, [level_token("DEBUG")]), (Level::Trace, [level_token("TRACE")]), ]; for &(s, expected) in &cases { assert_tokens(&s, &expected); } } #[test] fn test_level_case_insensitive() { let cases = [ (Level::Error, [level_token("error")]), (Level::Warn, [level_token("warn")]), (Level::Info, [level_token("info")]), (Level::Debug, [level_token("debug")]), (Level::Trace, [level_token("trace")]), ]; for &(s, expected) in &cases { assert_de_tokens(&s, &expected); } } #[test] fn test_level_de_bytes() { let cases = [ (Level::Error, level_bytes_tokens(b"ERROR")), (Level::Warn, level_bytes_tokens(b"WARN")), (Level::Info, level_bytes_tokens(b"INFO")), (Level::Debug, level_bytes_tokens(b"DEBUG")), (Level::Trace, level_bytes_tokens(b"TRACE")), ]; for &(value, tokens) in &cases { assert_de_tokens(&value, &tokens); } } #[test] fn test_level_de_variant_index() { let cases = [ (Level::Error, level_variant_tokens(0)), (Level::Warn, level_variant_tokens(1)), (Level::Info, level_variant_tokens(2)), (Level::Debug, level_variant_tokens(3)), (Level::Trace, level_variant_tokens(4)), ]; for &(value, tokens) in &cases { assert_de_tokens(&value, &tokens); } } #[test] fn test_level_de_error() { let msg = "unknown variant `errorx`, expected one of \ `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; assert_de_tokens_error::(&[level_token("errorx")], msg); } #[test] fn test_level_filter_ser_de() { let cases = [ (LevelFilter::Off, [level_filter_token("OFF")]), (LevelFilter::Error, [level_filter_token("ERROR")]), (LevelFilter::Warn, [level_filter_token("WARN")]), (LevelFilter::Info, [level_filter_token("INFO")]), (LevelFilter::Debug, [level_filter_token("DEBUG")]), (LevelFilter::Trace, [level_filter_token("TRACE")]), ]; for &(s, expected) in &cases { assert_tokens(&s, &expected); } } #[test] fn test_level_filter_case_insensitive() { let cases = [ (LevelFilter::Off, [level_filter_token("off")]), (LevelFilter::Error, [level_filter_token("error")]), (LevelFilter::Warn, [level_filter_token("warn")]), (LevelFilter::Info, [level_filter_token("info")]), (LevelFilter::Debug, [level_filter_token("debug")]), (LevelFilter::Trace, [level_filter_token("trace")]), ]; for &(s, expected) in &cases { assert_de_tokens(&s, &expected); } } #[test] fn test_level_filter_de_bytes() { let cases = [ (LevelFilter::Off, level_filter_bytes_tokens(b"OFF")), (LevelFilter::Error, level_filter_bytes_tokens(b"ERROR")), (LevelFilter::Warn, level_filter_bytes_tokens(b"WARN")), (LevelFilter::Info, level_filter_bytes_tokens(b"INFO")), (LevelFilter::Debug, level_filter_bytes_tokens(b"DEBUG")), (LevelFilter::Trace, level_filter_bytes_tokens(b"TRACE")), ]; for &(value, tokens) in &cases { assert_de_tokens(&value, &tokens); } } #[test] fn test_level_filter_de_variant_index() { let cases = [ (LevelFilter::Off, level_filter_variant_tokens(0)), (LevelFilter::Error, level_filter_variant_tokens(1)), (LevelFilter::Warn, level_filter_variant_tokens(2)), (LevelFilter::Info, level_filter_variant_tokens(3)), (LevelFilter::Debug, level_filter_variant_tokens(4)), (LevelFilter::Trace, level_filter_variant_tokens(5)), ]; for &(value, tokens) in &cases { assert_de_tokens(&value, &tokens); } } #[test] fn test_level_filter_de_error() { let msg = "unknown variant `errorx`, expected one of \ `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`"; assert_de_tokens_error::(&[level_filter_token("errorx")], msg); } }