2 use std
::str::{self, FromStr}
;
7 /// A parsed TOML datetime value
9 /// This structure is intended to represent the datetime primitive type that can
10 /// be encoded into TOML documents. This type is a parsed version that contains
11 /// all metadata internally.
13 /// Currently this type is intentionally conservative and only supports
14 /// `to_string` as an accessor. Over time though it's intended that it'll grow
17 /// Note that if you're using `Deserialize` to deserialize a TOML document, you
18 /// can use this as a placeholder for where you're expecting a datetime to be
21 /// Also note though that while this type implements `Serialize` and
22 /// `Deserialize` it's only recommended to use this type with the TOML format,
23 /// otherwise encoded in other formats it may look a little odd.
24 #[derive(PartialEq, Clone)]
28 offset
: Option
<Offset
>,
31 /// Error returned from parsing a `Datetime` in the `FromStr` implementation.
32 #[derive(Debug, Clone)]
33 pub struct DatetimeParseError
{
37 // Currently serde itself doesn't have a datetime type, so we map our `Datetime`
38 // to a special valid in the serde data model. Namely one with thiese special
39 // fields/struct names.
41 // In general the TOML encoder/decoder will catch this and not literally emit
42 // these strings but rather emit datetimes as they're intended.
43 pub const SERDE_STRUCT_FIELD_NAME
: &'
static str = "$__toml_private_datetime";
44 pub const SERDE_STRUCT_NAME
: &'
static str = "$__toml_private_Datetime";
46 #[derive(PartialEq, Clone)]
53 #[derive(PartialEq, Clone)]
61 #[derive(PartialEq, Clone)]
64 Custom { hours: i8, minutes: u8 }
,
67 impl fmt
::Debug
for Datetime
{
68 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
69 fmt
::Display
::fmt(self, f
)
73 impl fmt
::Display
for Datetime
{
74 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
75 if let Some(ref date
) = self.date
{
76 write
!(f
, "{}", date
)?
;
78 if let Some(ref time
) = self.time
{
79 if self.date
.is_some() {
82 write
!(f
, "{}", time
)?
;
84 if let Some(ref offset
) = self.offset
{
85 write
!(f
, "{}", offset
)?
;
91 impl fmt
::Display
for Date
{
92 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
93 write
!(f
, "{:04}-{:02}-{:02}", self.year
, self.month
, self.day
)
97 impl fmt
::Display
for Time
{
98 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
99 write
!(f
, "{:02}:{:02}:{:02}", self.hour
, self.minute
, self.second
)?
;
100 if self.nanosecond
!= 0 {
101 let s
= format
!("{:09}", self.nanosecond
);
102 write
!(f
, ".{}", s
.trim_right_matches('
0'
))?
;
108 impl fmt
::Display
for Offset
{
109 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
111 Offset
::Z
=> write
!(f
, "Z"),
112 Offset
::Custom { hours, minutes }
=> {
113 write
!(f
, "{:+03}:{:02}", hours
, minutes
)
119 impl FromStr
for Datetime
{
120 type Err
= DatetimeParseError
;
122 fn from_str(date
: &str) -> Result
<Datetime
, DatetimeParseError
> {
125 // 0000-00-00T00:00:00.00Z
126 // 0000-00-00T00:00:00.00
130 return Err(DatetimeParseError { _private: () }
)
132 let mut offset_allowed
= true;
133 let mut chars
= date
.chars();
135 // First up, parse the full date if we can
136 let full_date
= if chars
.clone().nth(2) == Some('
:'
) {
137 offset_allowed
= false;
140 let y1
= digit(&mut chars
)?
as u16;
141 let y2
= digit(&mut chars
)?
as u16;
142 let y3
= digit(&mut chars
)?
as u16;
143 let y4
= digit(&mut chars
)?
as u16;
147 _
=> return Err(DatetimeParseError { _private: () }
),
150 let m1
= digit(&mut chars
)?
;
151 let m2
= digit(&mut chars
)?
;
155 _
=> return Err(DatetimeParseError { _private: () }
),
158 let d1
= digit(&mut chars
)?
;
159 let d2
= digit(&mut chars
)?
;
162 year
: y1
* 1000 + y2
* 100 + y3
* 10 + y4
,
167 if date
.month
< 1 || date
.month
> 12 {
168 return Err(DatetimeParseError { _private: () }
)
170 if date
.day
< 1 || date
.day
> 31 {
171 return Err(DatetimeParseError { _private: () }
)
177 // Next parse the "partial-time" if available
178 let partial_time
= if full_date
.is_some() &&
179 chars
.clone().next() == Some('T'
) {
186 let time
= if partial_time
{
187 let h1
= digit(&mut chars
)?
;
188 let h2
= digit(&mut chars
)?
;
191 _
=> return Err(DatetimeParseError { _private: () }
),
193 let m1
= digit(&mut chars
)?
;
194 let m2
= digit(&mut chars
)?
;
197 _
=> return Err(DatetimeParseError { _private: () }
),
199 let s1
= digit(&mut chars
)?
;
200 let s2
= digit(&mut chars
)?
;
202 let mut nanosecond
= 0;
203 if chars
.clone().next() == Some('
.'
) {
205 let whole
= chars
.as_str();
207 let mut end
= whole
.len();
208 for (i
, byte
) in whole
.bytes().enumerate() {
212 let p
= 10_u32.pow(8 - i
as u32);
213 nanosecond
+= p
* (byte
- b'
0'
) as u32;
223 return Err(DatetimeParseError { _private: () }
)
225 chars
= whole
[end
..].chars();
230 minute
: m1
* 10 + m2
,
231 second
: s1
* 10 + s2
,
232 nanosecond
: nanosecond
,
236 return Err(DatetimeParseError { _private: () }
)
238 if time
.minute
> 59 {
239 return Err(DatetimeParseError { _private: () }
)
241 if time
.second
> 59 {
242 return Err(DatetimeParseError { _private: () }
)
244 if time
.nanosecond
> 999_999_999 {
245 return Err(DatetimeParseError { _private: () }
)
250 offset_allowed
= false;
254 // And finally, parse the offset
255 let offset
= if offset_allowed
{
256 let next
= chars
.clone().next();
257 if next
== Some('Z'
) {
260 } else if next
.is_none() {
263 let sign
= match next
{
266 _
=> return Err(DatetimeParseError { _private: () }
),
269 let h1
= digit(&mut chars
)?
as i8;
270 let h2
= digit(&mut chars
)?
as i8;
273 _
=> return Err(DatetimeParseError { _private: () }
),
275 let m1
= digit(&mut chars
)?
;
276 let m2
= digit(&mut chars
)?
;
278 Some(Offset
::Custom
{
279 hours
: sign
* (h1
* 10 + h2
),
280 minutes
: m1
* 10 + m2
,
287 // Return an error if we didn't hit eof, otherwise return our parsed
289 if chars
.next().is_some() {
290 return Err(DatetimeParseError { _private: () }
)
301 fn digit(chars
: &mut str::Chars
) -> Result
<u8, DatetimeParseError
> {
303 Some(c
) if '
0'
<= c
&& c
<= '
9'
=> Ok(c
as u8 - b'
0'
),
304 _
=> Err(DatetimeParseError { _private: () }
),
308 impl ser
::Serialize
for Datetime
{
309 fn serialize
<S
>(&self, serializer
: S
) -> Result
<S
::Ok
, S
::Error
>
310 where S
: ser
::Serializer
312 use serde
::ser
::SerializeStruct
;
314 let mut s
= serializer
.serialize_struct(SERDE_STRUCT_NAME
, 1)?
;
315 s
.serialize_field(SERDE_STRUCT_FIELD_NAME
, &self.to_string())?
;
320 impl<'de
> de
::Deserialize
<'de
> for Datetime
{
321 fn deserialize
<D
>(deserializer
: D
) -> Result
<Datetime
, D
::Error
>
322 where D
: de
::Deserializer
<'de
>
324 struct DatetimeVisitor
;
326 impl<'de
> de
::Visitor
<'de
> for DatetimeVisitor
{
327 type Value
= Datetime
;
329 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
330 formatter
.write_str("a TOML datetime")
333 fn visit_map
<V
>(self, mut visitor
: V
) -> Result
<Datetime
, V
::Error
>
334 where V
: de
::MapAccess
<'de
>
336 let value
= visitor
.next_key
::<DatetimeKey
>()?
;
338 return Err(de
::Error
::custom("datetime key not found"))
340 let v
: DatetimeFromString
= visitor
.next_value()?
;
346 static FIELDS
: [&'
static str; 1] = [SERDE_STRUCT_FIELD_NAME
];
347 deserializer
.deserialize_struct(SERDE_STRUCT_NAME
,
355 impl<'de
> de
::Deserialize
<'de
> for DatetimeKey
{
356 fn deserialize
<D
>(deserializer
: D
) -> Result
<DatetimeKey
, D
::Error
>
357 where D
: de
::Deserializer
<'de
>
361 impl<'de
> de
::Visitor
<'de
> for FieldVisitor
{
364 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
365 formatter
.write_str("a valid datetime field")
368 fn visit_str
<E
>(self, s
: &str) -> Result
<(), E
>
371 if s
== SERDE_STRUCT_FIELD_NAME
{
374 Err(de
::Error
::custom("expected field with custom name"))
379 deserializer
.deserialize_identifier(FieldVisitor
)?
;
384 pub struct DatetimeFromString
{
388 impl<'de
> de
::Deserialize
<'de
> for DatetimeFromString
{
389 fn deserialize
<D
>(deserializer
: D
) -> Result
<DatetimeFromString
, D
::Error
>
390 where D
: de
::Deserializer
<'de
>
394 impl<'de
> de
::Visitor
<'de
> for Visitor
{
395 type Value
= DatetimeFromString
;
397 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
{
398 formatter
.write_str("string containing a datetime")
401 fn visit_str
<E
>(self, s
: &str) -> Result
<DatetimeFromString
, E
>
405 Ok(date
) => Ok(DatetimeFromString { value: date }
),
406 Err(e
) => Err(de
::Error
::custom(e
)),
411 deserializer
.deserialize_str(Visitor
)
415 impl fmt
::Display
for DatetimeParseError
{
416 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
417 "failed to parse datetime".fmt(f
)
421 impl error
::Error
for DatetimeParseError
{
422 fn description(&self) -> &str {
423 "failed to parse datetime"