1 // Copyright (C) 2018 François Laignel <fengalin@free.fr> 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 use std::convert::{TryFrom, TryInto}; 10 11 use glib::translate::{FromGlib, ToGlib}; 12 use glib::value::{SetValue, SetValueOptional}; 13 use glib::StaticType; 14 15 use serde::de::{Deserialize, Deserializer, Error}; 16 use serde::ser; 17 use serde::ser::{Serialize, Serializer}; 18 use DateTime; 19 20 #[derive(Serialize, Deserialize)] 21 enum DateTimeVariants { 22 Y(i32), 23 YM(i32, i32), 24 YMD(i32, i32, i32), 25 YMDhmTz(i32, i32, i32, i32, i32, f32), 26 YMDhmsTz(i32, i32, i32, i32, i32, f64, f32), 27 } 28 29 // Note: ser / de for `glib::Date` should be implemented in the `glib` crate 30 // However, there is no `ser_de` feature in `glib` right now. The limitation is that 31 // `Date` fields can only be ser / de when they are used in `Value`s (which implies 32 // `Array`s, `List`s, `Structure` fields and `Tag`s) 33 pub(crate) struct Date(glib::Date); 34 35 impl From<glib::Date> for Date { from(glib_date: glib::Date) -> Self36 fn from(glib_date: glib::Date) -> Self { 37 Date(glib_date) 38 } 39 } 40 41 impl SetValue for Date { set_value(value: &mut glib::Value, this: &Self)42 unsafe fn set_value(value: &mut glib::Value, this: &Self) { 43 glib::value::SetValue::set_value(value, &this.0); 44 } 45 } 46 47 impl SetValueOptional for Date { set_value_optional(value: &mut glib::Value, this: Option<&Self>)48 unsafe fn set_value_optional(value: &mut glib::Value, this: Option<&Self>) { 49 glib::value::SetValueOptional::set_value_optional(value, this.map(|this| &this.0)); 50 } 51 } 52 53 impl StaticType for Date { static_type() -> glib::Type54 fn static_type() -> glib::Type { 55 glib::Date::static_type() 56 } 57 } 58 59 impl<'a> Serialize for Date { serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>60 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 61 DateTimeVariants::YMD( 62 self.0.get_year() as i32, 63 self.0.get_month().to_glib() as i32, 64 self.0.get_day() as i32, 65 ) 66 .serialize(serializer) 67 } 68 } 69 70 impl<'a> Serialize for DateTime { serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>71 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { 72 let variant = if self.has_second() { 73 DateTimeVariants::YMDhmsTz( 74 self.get_year(), 75 self.get_month(), 76 self.get_day(), 77 self.get_hour(), 78 self.get_minute(), 79 f64::from(self.get_second()) + f64::from(self.get_microsecond()) / 1_000_000f64, 80 self.get_time_zone_offset(), 81 ) 82 } else if self.has_time() { 83 DateTimeVariants::YMDhmTz( 84 self.get_year(), 85 self.get_month(), 86 self.get_day(), 87 self.get_hour(), 88 self.get_minute(), 89 self.get_time_zone_offset(), 90 ) 91 } else if self.has_day() { 92 DateTimeVariants::YMD(self.get_year(), self.get_month(), self.get_day()) 93 } else if self.has_month() { 94 DateTimeVariants::YM(self.get_year(), self.get_month()) 95 } else if self.has_year() { 96 DateTimeVariants::Y(self.get_year()) 97 } else { 98 return Err(ser::Error::custom(format!( 99 "no parts could be found in `DateTime` {}", 100 self, 101 ))); 102 }; 103 104 variant.serialize(serializer) 105 } 106 } 107 108 impl TryFrom<DateTimeVariants> for Date { 109 type Error = &'static str; 110 try_from(dt_variant: DateTimeVariants) -> Result<Self, Self::Error>111 fn try_from(dt_variant: DateTimeVariants) -> Result<Self, Self::Error> { 112 match dt_variant { 113 DateTimeVariants::YMD(y, m, d) => { 114 let month = glib::DateMonth::from_glib(m); 115 if let glib::DateMonth::__Unknown(_) = month { 116 return Err("Out of range `month` for `Date`"); 117 } 118 119 Ok(Date(glib::Date::new_dmy( 120 d.try_into().map_err(|_| "Out of range `day` for `Date`")?, 121 month, 122 y.try_into().map_err(|_| "Out of range `year` for `Date`")?, 123 ))) 124 } 125 _ => Err("Incompatible variant for `Date` (expecting \"YMD\")"), 126 } 127 } 128 } 129 130 impl<'de> Deserialize<'de> for Date { deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>131 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { 132 DateTimeVariants::deserialize(deserializer) 133 .and_then(|dt_variant| dt_variant.try_into().map_err(D::Error::custom)) 134 } 135 } 136 137 #[allow(clippy::many_single_char_names)] 138 impl From<DateTimeVariants> for DateTime { from(dt_variant: DateTimeVariants) -> Self139 fn from(dt_variant: DateTimeVariants) -> Self { 140 match dt_variant { 141 DateTimeVariants::Y(y) => DateTime::new_y(y), 142 DateTimeVariants::YM(y, m) => DateTime::new_ym(y, m), 143 DateTimeVariants::YMD(y, m, d) => DateTime::new_ymd(y, m, d), 144 DateTimeVariants::YMDhmTz(y, m, d, h, mn, tz) => { 145 DateTime::new(tz, y, m, d, h, mn, -1f64) 146 } 147 DateTimeVariants::YMDhmsTz(y, m, d, h, mn, s, tz) => { 148 DateTime::new(tz, y, m, d, h, mn, s) 149 } 150 } 151 } 152 } 153 154 impl<'de> Deserialize<'de> for DateTime { deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>155 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { 156 DateTimeVariants::deserialize(deserializer).map(|dt_variant| dt_variant.into()) 157 } 158 } 159 160 #[cfg(test)] 161 mod tests { 162 extern crate ron; 163 extern crate serde_json; 164 165 use DateTime; 166 167 #[test] test_serialize()168 fn test_serialize() { 169 ::init().unwrap(); 170 171 let mut pretty_config = ron::ser::PrettyConfig::default(); 172 pretty_config.new_line = "".to_string(); 173 174 let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64); 175 let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); 176 assert_eq!( 177 Ok("YMDhmsTz(2018, 5, 28, 16, 6, 42.123456, 2)".to_owned()), 178 res, 179 ); 180 181 let res = serde_json::to_string(&datetime).unwrap(); 182 assert_eq!( 183 r#"{"YMDhmsTz":[2018,5,28,16,6,42.123456,2.0]}"#.to_owned(), 184 res 185 ); 186 187 let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64); 188 let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); 189 assert_eq!(Ok("YMDhmTz(2018, 5, 28, 16, 6, 2)".to_owned()), res,); 190 191 let datetime = DateTime::new_ymd(2018, 5, 28); 192 let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); 193 assert_eq!(Ok("YMD(2018, 5, 28)".to_owned()), res); 194 195 let datetime = DateTime::new_ym(2018, 5); 196 let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); 197 assert_eq!(Ok("YM(2018, 5)".to_owned()), res); 198 199 let datetime = DateTime::new_y(2018); 200 let res = ron::ser::to_string_pretty(&datetime, pretty_config); 201 assert_eq!(Ok("Y(2018)".to_owned()), res); 202 } 203 204 #[test] test_deserialize()205 fn test_deserialize() { 206 ::init().unwrap(); 207 208 let datetime_ron = "YMDhmsTz(2018, 5, 28, 16, 6, 42.123456, 2)"; 209 let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); 210 assert_eq!( 211 datetime_de, 212 DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64) 213 ); 214 215 let datetime_json = r#"{"YMDhmsTz":[2018,5,28,16,6,42.123456,2.0]}"#; 216 let datetime_de: DateTime = serde_json::from_str(datetime_json).unwrap(); 217 assert_eq!( 218 datetime_de, 219 DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64) 220 ); 221 222 let datetime_ron = "YMDhmTz(2018, 5, 28, 16, 6, 2)"; 223 let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); 224 assert_eq!(datetime_de, DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64)); 225 226 let datetime_ron = "YMD(2018, 5, 28)"; 227 let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); 228 assert_eq!(datetime_de, DateTime::new_ymd(2018, 5, 28)); 229 230 let datetime_ron = "YM(2018, 5)"; 231 let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); 232 assert_eq!(datetime_de, DateTime::new_ym(2018, 5)); 233 234 let datetime_ron = "Y(2018)"; 235 let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); 236 assert_eq!(datetime_de, DateTime::new_y(2018)); 237 } 238 239 #[test] test_serde_roundtrip()240 fn test_serde_roundtrip() { 241 ::init().unwrap(); 242 243 let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64); 244 let datetime_ser = ron::ser::to_string(&datetime).unwrap(); 245 let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); 246 assert_eq!(datetime_de, datetime); 247 248 let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, -1f64); 249 let datetime_ser = ron::ser::to_string(&datetime).unwrap(); 250 let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); 251 assert_eq!(datetime_de, datetime); 252 253 let datetime = DateTime::new_ymd(2018, 5, 28); 254 let datetime_ser = ron::ser::to_string(&datetime).unwrap(); 255 let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); 256 assert_eq!(datetime_de, datetime); 257 258 let datetime = DateTime::new_ym(2018, 5); 259 let datetime_ser = ron::ser::to_string(&datetime).unwrap(); 260 let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); 261 assert_eq!(datetime_de, datetime); 262 263 let datetime = DateTime::new_y(2018); 264 let datetime_ser = ron::ser::to_string(&datetime).unwrap(); 265 let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); 266 assert_eq!(datetime_de, datetime); 267 } 268 } 269