1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
use std::{ fmt, ops::{Deref, DerefMut}, str::FromStr, }; use chrono::NaiveDate as ChronoNaiveDate; use serde::{ de::{self, Visitor}, Deserialize, Deserializer, }; #[derive(PartialEq, Debug, Clone)] pub struct NaiveDate(pub ChronoNaiveDate); impl From<ChronoNaiveDate> for NaiveDate { fn from(inner: ChronoNaiveDate) -> Self { Self(inner) } } impl Deref for NaiveDate { type Target = ChronoNaiveDate; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for NaiveDate { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } pub type ParseError = chrono::ParseError; impl FromStr for NaiveDate { type Err = ParseError; fn from_str(s: &str) -> Result<Self, Self::Err> { ChronoNaiveDate::parse_from_str(s, "%Y-%m-%d").map(Into::into) } } struct NaiveDateVisitor; impl<'de> Visitor<'de> for NaiveDateVisitor { type Value = NaiveDate; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("format %Y-%m-%d") } fn visit_str<E>(self, string: &str) -> Result<Self::Value, E> where E: de::Error, { string .parse() .map_err(|err: ParseError| de::Error::custom(err.to_string())) } } impl<'de> Deserialize<'de> for NaiveDate { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { deserializer.deserialize_str(NaiveDateVisitor) } } pub fn deserialize<'de, D>(d: D) -> Result<ChronoNaiveDate, D::Error> where D: de::Deserializer<'de>, { d.deserialize_str(NaiveDateVisitor).map(|x| x.0) } #[cfg(test)] mod tests { use super::*; use std::{error, fs, path::PathBuf}; use chrono::NaiveDate; #[test] fn test_parse() -> Result<(), Box<dyn error::Error>> { assert_eq!( "2021-03-01" .parse::<NaiveDate>() .map_err(|err| err.to_string())?, NaiveDate::from_ymd(2021, 3, 1).into() ); Ok(()) } #[derive(Deserialize)] struct Row { #[serde(deserialize_with = "crate::date::deserialize")] date: chrono::NaiveDate, } #[test] fn test_de() -> Result<(), Box<dyn error::Error>> { let deserializer = de::IntoDeserializer::<de::value::Error>::into_deserializer; assert_eq!( super::deserialize(deserializer("2021-03-01")).unwrap(), NaiveDate::from_ymd(2021, 3, 1) ); let content = fs::read_to_string(PathBuf::new().join("tests/files/date.txt"))?; let line = content.lines().next().unwrap(); let Row { date } = serde_json::from_str(line)?; assert_eq!(date, NaiveDate::from_ymd(2021, 3, 1)); Ok(()) } }