diff --git a/src/lib.rs b/src/lib.rs index 82b6622f..6807305d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -495,6 +495,8 @@ extern crate wasm_bindgen; #[cfg_attr(feature = "__doctest", cfg(doctest))] doctest!("../README.md"); +use core::fmt; + // this reexport is to aid the transition and should not be in the prelude! pub use oldtime::Duration; @@ -649,305 +651,8 @@ impl fmt::Display for SerdeError { } } -/// The day of week. -/// -/// The order of the days of week depends on the context. -/// (This is why this type does *not* implement `PartialOrd` or `Ord` traits.) -/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result. -#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] -#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] -pub enum Weekday { - /// Monday. - Mon = 0, - /// Tuesday. - Tue = 1, - /// Wednesday. - Wed = 2, - /// Thursday. - Thu = 3, - /// Friday. - Fri = 4, - /// Saturday. - Sat = 5, - /// Sunday. - Sun = 6, -} - -impl Weekday { - /// The next day in the week. - /// - /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` - /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- - /// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon` - #[inline] - pub fn succ(&self) -> Weekday { - match *self { - Weekday::Mon => Weekday::Tue, - Weekday::Tue => Weekday::Wed, - Weekday::Wed => Weekday::Thu, - Weekday::Thu => Weekday::Fri, - Weekday::Fri => Weekday::Sat, - Weekday::Sat => Weekday::Sun, - Weekday::Sun => Weekday::Mon, - } - } - - /// The previous day in the week. - /// - /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` - /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- - /// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` - #[inline] - pub fn pred(&self) -> Weekday { - match *self { - Weekday::Mon => Weekday::Sun, - Weekday::Tue => Weekday::Mon, - Weekday::Wed => Weekday::Tue, - Weekday::Thu => Weekday::Wed, - Weekday::Fri => Weekday::Thu, - Weekday::Sat => Weekday::Fri, - Weekday::Sun => Weekday::Sat, - } - } - - /// Returns a day-of-week number starting from Monday = 1. (ISO 8601 weekday number) - /// - /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` - /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- - /// `w.number_from_monday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 7 - #[inline] - pub fn number_from_monday(&self) -> u32 { - match *self { - Weekday::Mon => 1, - Weekday::Tue => 2, - Weekday::Wed => 3, - Weekday::Thu => 4, - Weekday::Fri => 5, - Weekday::Sat => 6, - Weekday::Sun => 7, - } - } - - /// Returns a day-of-week number starting from Sunday = 1. - /// - /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` - /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- - /// `w.number_from_sunday()`: | 2 | 3 | 4 | 5 | 6 | 7 | 1 - #[inline] - pub fn number_from_sunday(&self) -> u32 { - match *self { - Weekday::Mon => 2, - Weekday::Tue => 3, - Weekday::Wed => 4, - Weekday::Thu => 5, - Weekday::Fri => 6, - Weekday::Sat => 7, - Weekday::Sun => 1, - } - } - - /// Returns a day-of-week number starting from Monday = 0. - /// - /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` - /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- - /// `w.num_days_from_monday()`: | 0 | 1 | 2 | 3 | 4 | 5 | 6 - #[inline] - pub fn num_days_from_monday(&self) -> u32 { - match *self { - Weekday::Mon => 0, - Weekday::Tue => 1, - Weekday::Wed => 2, - Weekday::Thu => 3, - Weekday::Fri => 4, - Weekday::Sat => 5, - Weekday::Sun => 6, - } - } - - /// Returns a day-of-week number starting from Sunday = 0. - /// - /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` - /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- - /// `w.num_days_from_sunday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 0 - #[inline] - pub fn num_days_from_sunday(&self) -> u32 { - match *self { - Weekday::Mon => 1, - Weekday::Tue => 2, - Weekday::Wed => 3, - Weekday::Thu => 4, - Weekday::Fri => 5, - Weekday::Sat => 6, - Weekday::Sun => 0, - } - } -} - -impl fmt::Display for Weekday { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - Weekday::Mon => "Mon", - Weekday::Tue => "Tue", - Weekday::Wed => "Wed", - Weekday::Thu => "Thu", - Weekday::Fri => "Fri", - Weekday::Sat => "Sat", - Weekday::Sun => "Sun", - }) - } -} - -/// Any weekday can be represented as an integer from 0 to 6, which equals to -/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation. -/// Do not heavily depend on this though; use explicit methods whenever possible. -impl num_traits::FromPrimitive for Weekday { - #[inline] - fn from_i64(n: i64) -> Option { - match n { - 0 => Some(Weekday::Mon), - 1 => Some(Weekday::Tue), - 2 => Some(Weekday::Wed), - 3 => Some(Weekday::Thu), - 4 => Some(Weekday::Fri), - 5 => Some(Weekday::Sat), - 6 => Some(Weekday::Sun), - _ => None, - } - } - - #[inline] - fn from_u64(n: u64) -> Option { - match n { - 0 => Some(Weekday::Mon), - 1 => Some(Weekday::Tue), - 2 => Some(Weekday::Wed), - 3 => Some(Weekday::Thu), - 4 => Some(Weekday::Fri), - 5 => Some(Weekday::Sat), - 6 => Some(Weekday::Sun), - _ => None, - } - } -} - -use core::fmt; - -/// An error resulting from reading `Weekday` value with `FromStr`. -#[derive(Clone, PartialEq)] -pub struct ParseWeekdayError { - _dummy: (), -} - -impl fmt::Debug for ParseWeekdayError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ParseWeekdayError {{ .. }}") - } -} - -// the actual `FromStr` implementation is in the `format` module to leverage the existing code - -#[cfg(feature = "serde")] -mod weekday_serde { - use super::Weekday; - use core::fmt; - use serdelib::{de, ser}; - - impl ser::Serialize for Weekday { - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - serializer.collect_str(&self) - } - } - - struct WeekdayVisitor; - - impl<'de> de::Visitor<'de> for WeekdayVisitor { - type Value = Weekday; - - fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("Weekday") - } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - value.parse().map_err(|_| E::custom("short or long weekday names expected")) - } - } - - impl<'de> de::Deserialize<'de> for Weekday { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - deserializer.deserialize_str(WeekdayVisitor) - } - } - - #[cfg(test)] - extern crate serde_json; - - #[test] - fn test_serde_serialize() { - use self::serde_json::to_string; - use Weekday::*; - - let cases: Vec<(Weekday, &str)> = vec![ - (Mon, "\"Mon\""), - (Tue, "\"Tue\""), - (Wed, "\"Wed\""), - (Thu, "\"Thu\""), - (Fri, "\"Fri\""), - (Sat, "\"Sat\""), - (Sun, "\"Sun\""), - ]; - - for (weekday, expected_str) in cases { - let string = to_string(&weekday).unwrap(); - assert_eq!(string, expected_str); - } - } - - #[test] - fn test_serde_deserialize() { - use self::serde_json::from_str; - use Weekday::*; - - let cases: Vec<(&str, Weekday)> = vec![ - ("\"mon\"", Mon), - ("\"MONDAY\"", Mon), - ("\"MonDay\"", Mon), - ("\"mOn\"", Mon), - ("\"tue\"", Tue), - ("\"tuesday\"", Tue), - ("\"wed\"", Wed), - ("\"wednesday\"", Wed), - ("\"thu\"", Thu), - ("\"thursday\"", Thu), - ("\"fri\"", Fri), - ("\"friday\"", Fri), - ("\"sat\"", Sat), - ("\"saturday\"", Sat), - ("\"sun\"", Sun), - ("\"sunday\"", Sun), - ]; - - for (str, expected_weekday) in cases { - let weekday = from_str::(str).unwrap(); - assert_eq!(weekday, expected_weekday); - } - - let errors: Vec<&str> = - vec!["\"not a weekday\"", "\"monDAYs\"", "\"mond\"", "mon", "\"thur\"", "\"thurs\""]; - - for str in errors { - from_str::(str).unwrap_err(); - } - } -} +mod weekday; +pub use weekday::{Weekday, ParseWeekdayError}; /// The month of the year. /// diff --git a/src/weekday.rs b/src/weekday.rs new file mode 100644 index 00000000..c719ce89 --- /dev/null +++ b/src/weekday.rs @@ -0,0 +1,299 @@ +use core::fmt; + +/// The day of week. +/// +/// The order of the days of week depends on the context. +/// (This is why this type does *not* implement `PartialOrd` or `Ord` traits.) +/// One should prefer `*_from_monday` or `*_from_sunday` methods to get the correct result. +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))] +pub enum Weekday { + /// Monday. + Mon = 0, + /// Tuesday. + Tue = 1, + /// Wednesday. + Wed = 2, + /// Thursday. + Thu = 3, + /// Friday. + Fri = 4, + /// Saturday. + Sat = 5, + /// Sunday. + Sun = 6, +} + +impl Weekday { + /// The next day in the week. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.succ()`: | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` | `Mon` + #[inline] + pub fn succ(&self) -> Weekday { + match *self { + Weekday::Mon => Weekday::Tue, + Weekday::Tue => Weekday::Wed, + Weekday::Wed => Weekday::Thu, + Weekday::Thu => Weekday::Fri, + Weekday::Fri => Weekday::Sat, + Weekday::Sat => Weekday::Sun, + Weekday::Sun => Weekday::Mon, + } + } + + /// The previous day in the week. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// ----------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.pred()`: | `Sun` | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` + #[inline] + pub fn pred(&self) -> Weekday { + match *self { + Weekday::Mon => Weekday::Sun, + Weekday::Tue => Weekday::Mon, + Weekday::Wed => Weekday::Tue, + Weekday::Thu => Weekday::Wed, + Weekday::Fri => Weekday::Thu, + Weekday::Sat => Weekday::Fri, + Weekday::Sun => Weekday::Sat, + } + } + + /// Returns a day-of-week number starting from Monday = 1. (ISO 8601 weekday number) + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.number_from_monday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 7 + #[inline] + pub fn number_from_monday(&self) -> u32 { + match *self { + Weekday::Mon => 1, + Weekday::Tue => 2, + Weekday::Wed => 3, + Weekday::Thu => 4, + Weekday::Fri => 5, + Weekday::Sat => 6, + Weekday::Sun => 7, + } + } + + /// Returns a day-of-week number starting from Sunday = 1. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// ------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.number_from_sunday()`: | 2 | 3 | 4 | 5 | 6 | 7 | 1 + #[inline] + pub fn number_from_sunday(&self) -> u32 { + match *self { + Weekday::Mon => 2, + Weekday::Tue => 3, + Weekday::Wed => 4, + Weekday::Thu => 5, + Weekday::Fri => 6, + Weekday::Sat => 7, + Weekday::Sun => 1, + } + } + + /// Returns a day-of-week number starting from Monday = 0. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.num_days_from_monday()`: | 0 | 1 | 2 | 3 | 4 | 5 | 6 + #[inline] + pub fn num_days_from_monday(&self) -> u32 { + match *self { + Weekday::Mon => 0, + Weekday::Tue => 1, + Weekday::Wed => 2, + Weekday::Thu => 3, + Weekday::Fri => 4, + Weekday::Sat => 5, + Weekday::Sun => 6, + } + } + + /// Returns a day-of-week number starting from Sunday = 0. + /// + /// `w`: | `Mon` | `Tue` | `Wed` | `Thu` | `Fri` | `Sat` | `Sun` + /// --------------------------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- + /// `w.num_days_from_sunday()`: | 1 | 2 | 3 | 4 | 5 | 6 | 0 + #[inline] + pub fn num_days_from_sunday(&self) -> u32 { + match *self { + Weekday::Mon => 1, + Weekday::Tue => 2, + Weekday::Wed => 3, + Weekday::Thu => 4, + Weekday::Fri => 5, + Weekday::Sat => 6, + Weekday::Sun => 0, + } + } +} + +impl fmt::Display for Weekday { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match *self { + Weekday::Mon => "Mon", + Weekday::Tue => "Tue", + Weekday::Wed => "Wed", + Weekday::Thu => "Thu", + Weekday::Fri => "Fri", + Weekday::Sat => "Sat", + Weekday::Sun => "Sun", + }) + } +} + +/// Any weekday can be represented as an integer from 0 to 6, which equals to +/// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation. +/// Do not heavily depend on this though; use explicit methods whenever possible. +impl num_traits::FromPrimitive for Weekday { + #[inline] + fn from_i64(n: i64) -> Option { + match n { + 0 => Some(Weekday::Mon), + 1 => Some(Weekday::Tue), + 2 => Some(Weekday::Wed), + 3 => Some(Weekday::Thu), + 4 => Some(Weekday::Fri), + 5 => Some(Weekday::Sat), + 6 => Some(Weekday::Sun), + _ => None, + } + } + + #[inline] + fn from_u64(n: u64) -> Option { + match n { + 0 => Some(Weekday::Mon), + 1 => Some(Weekday::Tue), + 2 => Some(Weekday::Wed), + 3 => Some(Weekday::Thu), + 4 => Some(Weekday::Fri), + 5 => Some(Weekday::Sat), + 6 => Some(Weekday::Sun), + _ => None, + } + } +} + +/// An error resulting from reading `Weekday` value with `FromStr`. +#[derive(Clone, PartialEq)] +pub struct ParseWeekdayError { + pub(crate) _dummy: (), +} + +impl fmt::Debug for ParseWeekdayError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ParseWeekdayError {{ .. }}") + } +} + +// the actual `FromStr` implementation is in the `format` module to leverage the existing code + +#[cfg(feature = "serde")] +mod weekday_serde { + use super::Weekday; + use core::fmt; + use serdelib::{de, ser}; + + impl ser::Serialize for Weekday { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + serializer.collect_str(&self) + } + } + + struct WeekdayVisitor; + + impl<'de> de::Visitor<'de> for WeekdayVisitor { + type Value = Weekday; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("Weekday") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + value.parse().map_err(|_| E::custom("short or long weekday names expected")) + } + } + + impl<'de> de::Deserialize<'de> for Weekday { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_str(WeekdayVisitor) + } + } + + #[cfg(test)] + extern crate serde_json; + + #[test] + fn test_serde_serialize() { + use self::serde_json::to_string; + use Weekday::*; + + let cases: Vec<(Weekday, &str)> = vec![ + (Mon, "\"Mon\""), + (Tue, "\"Tue\""), + (Wed, "\"Wed\""), + (Thu, "\"Thu\""), + (Fri, "\"Fri\""), + (Sat, "\"Sat\""), + (Sun, "\"Sun\""), + ]; + + for (weekday, expected_str) in cases { + let string = to_string(&weekday).unwrap(); + assert_eq!(string, expected_str); + } + } + + #[test] + fn test_serde_deserialize() { + use self::serde_json::from_str; + use Weekday::*; + + let cases: Vec<(&str, Weekday)> = vec![ + ("\"mon\"", Mon), + ("\"MONDAY\"", Mon), + ("\"MonDay\"", Mon), + ("\"mOn\"", Mon), + ("\"tue\"", Tue), + ("\"tuesday\"", Tue), + ("\"wed\"", Wed), + ("\"wednesday\"", Wed), + ("\"thu\"", Thu), + ("\"thursday\"", Thu), + ("\"fri\"", Fri), + ("\"friday\"", Fri), + ("\"sat\"", Sat), + ("\"saturday\"", Sat), + ("\"sun\"", Sun), + ("\"sunday\"", Sun), + ]; + + for (str, expected_weekday) in cases { + let weekday = from_str::(str).unwrap(); + assert_eq!(weekday, expected_weekday); + } + + let errors: Vec<&str> = + vec!["\"not a weekday\"", "\"monDAYs\"", "\"mond\"", "mon", "\"thur\"", "\"thurs\""]; + + for str in errors { + from_str::(str).unwrap_err(); + } + } +}