2019-05-07 17:36:32 +02:00
use serde ::Serialize ;
use serde ::{ Deserialize , Deserializer , Serializer } ;
2019-05-07 18:44:59 +02:00
use std ::str ::FromStr ;
2019-05-07 17:36:32 +02:00
#[ derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd) ]
pub struct Date {
pub year : u16 ,
pub month : u8 ,
pub day : u8 ,
}
impl Date {
#[ cfg(test) ]
pub fn new ( year : u16 , month : u8 , day : u8 ) -> Self {
Date { year , month , day }
}
2019-05-07 18:44:59 +02:00
}
#[ derive(Clone, PartialEq, Eq, Debug) ]
pub enum DateParseError {
InvalidNumber ,
MonthOutOfRange ,
DayOutOfRange ,
WrongFormat ,
}
2019-05-07 17:36:32 +02:00
2019-05-07 18:44:59 +02:00
impl FromStr for Date {
type Err = DateParseError ;
fn from_str ( input : & str ) -> Result < Date , DateParseError > {
2019-05-07 17:36:32 +02:00
let mut parts = input . splitn ( 3 , " - " ) ;
2019-05-07 18:44:59 +02:00
let year = parts
. next ( )
. ok_or ( DateParseError ::WrongFormat ) ?
. parse ::< u16 > ( )
. map_err ( | _ | DateParseError ::InvalidNumber ) ? ;
let month = parts
. next ( )
. ok_or ( DateParseError ::WrongFormat ) ?
. parse ::< u8 > ( )
. map_err ( | _ | DateParseError ::InvalidNumber ) ? ;
let day = parts
. next ( )
. ok_or ( DateParseError ::WrongFormat ) ?
. parse ::< u8 > ( )
. map_err ( | _ | DateParseError ::InvalidNumber ) ? ;
2019-05-07 17:36:32 +02:00
if month > 12 {
2019-05-07 18:44:59 +02:00
return Err ( DateParseError ::DayOutOfRange ) ;
2019-05-07 17:36:32 +02:00
}
if day > 31 {
2019-05-07 18:44:59 +02:00
return Err ( DateParseError ::MonthOutOfRange ) ;
2019-05-07 17:36:32 +02:00
}
2019-05-07 18:44:59 +02:00
Ok ( Date { year , month , day } )
2019-05-07 17:36:32 +02:00
}
}
impl Serialize for Date {
fn serialize < S > ( & self , serializer : S ) -> Result < S ::Ok , S ::Error >
where
S : Serializer ,
{
2019-05-08 15:03:18 +02:00
let data = ( self . year , self . month , self . day ) ;
data . serialize ( serializer )
2019-05-07 17:36:32 +02:00
}
}
impl < ' de > Deserialize < ' de > for Date {
fn deserialize < D > ( deserializer : D ) -> Result < Date , D ::Error >
where
D : Deserializer < ' de > ,
{
2019-05-08 15:03:18 +02:00
let data = < ( u16 , u8 , u8 ) > ::deserialize ( deserializer ) ? ;
2019-05-07 17:36:32 +02:00
2019-05-08 15:03:18 +02:00
Ok ( Date {
year : data . 0 ,
month : data . 1 ,
day : data . 2 ,
} )
2019-05-07 17:36:32 +02:00
}
}
#[ cfg(test) ]
mod test {
use super ::* ;
#[ test ]
fn order ( ) {
// Other Test not needed, since the Ord is derived.
assert! ( Date ::new ( 2019 , 10 , 10 ) > Date ::new ( 2018 , 10 , 10 ) ) ;
assert! ( Date ::new ( 2018 , 11 , 10 ) > Date ::new ( 2018 , 10 , 10 ) ) ;
assert! ( Date ::new ( 2018 , 10 , 11 ) > Date ::new ( 2018 , 10 , 10 ) ) ;
}
#[ test ]
fn from_str ( ) {
2019-05-07 18:44:59 +02:00
assert_eq! ( Ok ( Date ::new ( 2019 , 10 , 10 ) ) , Date ::from_str ( " 2019-10-10 " ) ) ;
assert_eq! ( Ok ( Date ::new ( 2019 , 1 , 1 ) ) , Date ::from_str ( " 2019-1-1 " ) ) ;
assert! ( Date ::from_str ( " 2019-1-1-444 " ) . is_err ( ) ) ;
2019-05-07 17:36:32 +02:00
assert_eq! (
2019-05-07 18:44:59 +02:00
Ok ( Date ::new ( 2019 , 1 , 1 ) ) ,
2019-05-07 17:36:32 +02:00
Date ::from_str ( " 2019-0000000000001-00000001 " )
) ;
2019-05-07 18:44:59 +02:00
assert! ( Date ::from_str ( " XXX-400-400 " ) . is_err ( ) ) ;
assert! ( Date ::from_str ( " 400-400-400 " ) . is_err ( ) ) ;
2019-05-07 17:36:32 +02:00
}
}