]> git.proxmox.com Git - cargo.git/blob - vendor/toml-0.4.5/src/datetime.rs
New upstream version 0.23.0
[cargo.git] / vendor / toml-0.4.5 / src / datetime.rs
1 use std::fmt;
2 use std::str::{self, FromStr};
3 use std::error;
4
5 use serde::{de, ser};
6
7 /// A parsed TOML datetime value
8 ///
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.
12 ///
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
15 /// more support!
16 ///
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
19 /// specified.
20 ///
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)]
25 pub struct Datetime {
26 date: Option<Date>,
27 time: Option<Time>,
28 offset: Option<Offset>,
29 }
30
31 /// Error returned from parsing a `Datetime` in the `FromStr` implementation.
32 #[derive(Debug, Clone)]
33 pub struct DatetimeParseError {
34 _private: (),
35 }
36
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.
40 //
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";
45
46 #[derive(PartialEq, Clone)]
47 struct Date {
48 year: u16,
49 month: u8,
50 day: u8,
51 }
52
53 #[derive(PartialEq, Clone)]
54 struct Time {
55 hour: u8,
56 minute: u8,
57 second: u8,
58 nanosecond: u32,
59 }
60
61 #[derive(PartialEq, Clone)]
62 enum Offset {
63 Z,
64 Custom { hours: i8, minutes: u8 },
65 }
66
67 impl fmt::Debug for Datetime {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 fmt::Display::fmt(self, f)
70 }
71 }
72
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)?;
77 }
78 if let Some(ref time) = self.time {
79 if self.date.is_some() {
80 write!(f, "T")?;
81 }
82 write!(f, "{}", time)?;
83 }
84 if let Some(ref offset) = self.offset {
85 write!(f, "{}", offset)?;
86 }
87 Ok(())
88 }
89 }
90
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)
94 }
95 }
96
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'))?;
103 }
104 Ok(())
105 }
106 }
107
108 impl fmt::Display for Offset {
109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
110 match *self {
111 Offset::Z => write!(f, "Z"),
112 Offset::Custom { hours, minutes } => {
113 write!(f, "{:+03}:{:02}", hours, minutes)
114 }
115 }
116 }
117 }
118
119 impl FromStr for Datetime {
120 type Err = DatetimeParseError;
121
122 fn from_str(date: &str) -> Result<Datetime, DatetimeParseError> {
123 // Accepted formats:
124 //
125 // 0000-00-00T00:00:00.00Z
126 // 0000-00-00T00:00:00.00
127 // 0000-00-00
128 // 00:00:00.00
129 if date.len() < 3 {
130 return Err(DatetimeParseError { _private: () })
131 }
132 let mut offset_allowed = true;
133 let mut chars = date.chars();
134
135 // First up, parse the full date if we can
136 let full_date = if chars.clone().nth(2) == Some(':') {
137 offset_allowed = false;
138 None
139 } else {
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;
144
145 match chars.next() {
146 Some('-') => {}
147 _ => return Err(DatetimeParseError { _private: () }),
148 }
149
150 let m1 = digit(&mut chars)?;
151 let m2 = digit(&mut chars)?;
152
153 match chars.next() {
154 Some('-') => {}
155 _ => return Err(DatetimeParseError { _private: () }),
156 }
157
158 let d1 = digit(&mut chars)?;
159 let d2 = digit(&mut chars)?;
160
161 let date = Date {
162 year: y1 * 1000 + y2 * 100 + y3 * 10 + y4,
163 month: m1 * 10 + m2,
164 day: d1 * 10 + d2,
165 };
166
167 if date.month < 1 || date.month > 12 {
168 return Err(DatetimeParseError { _private: () })
169 }
170 if date.day < 1 || date.day > 31 {
171 return Err(DatetimeParseError { _private: () })
172 }
173
174 Some(date)
175 };
176
177 // Next parse the "partial-time" if available
178 let partial_time = if full_date.is_some() &&
179 chars.clone().next() == Some('T') {
180 chars.next();
181 true
182 } else {
183 full_date.is_none()
184 };
185
186 let time = if partial_time {
187 let h1 = digit(&mut chars)?;
188 let h2 = digit(&mut chars)?;
189 match chars.next() {
190 Some(':') => {}
191 _ => return Err(DatetimeParseError { _private: () }),
192 }
193 let m1 = digit(&mut chars)?;
194 let m2 = digit(&mut chars)?;
195 match chars.next() {
196 Some(':') => {}
197 _ => return Err(DatetimeParseError { _private: () }),
198 }
199 let s1 = digit(&mut chars)?;
200 let s2 = digit(&mut chars)?;
201
202 let mut nanosecond = 0;
203 if chars.clone().next() == Some('.') {
204 chars.next();
205 let whole = chars.as_str();
206
207 let mut end = whole.len();
208 for (i, byte) in whole.bytes().enumerate() {
209 match byte {
210 b'0' ... b'9' => {
211 if i < 9 {
212 let p = 10_u32.pow(8 - i as u32);
213 nanosecond += p * (byte - b'0') as u32;
214 }
215 }
216 _ => {
217 end = i;
218 break;
219 }
220 }
221 }
222 if end == 0 {
223 return Err(DatetimeParseError { _private: () })
224 }
225 chars = whole[end..].chars();
226 }
227
228 let time = Time {
229 hour: h1 * 10 + h2,
230 minute: m1 * 10 + m2,
231 second: s1 * 10 + s2,
232 nanosecond: nanosecond,
233 };
234
235 if time.hour > 24 {
236 return Err(DatetimeParseError { _private: () })
237 }
238 if time.minute > 59 {
239 return Err(DatetimeParseError { _private: () })
240 }
241 if time.second > 59 {
242 return Err(DatetimeParseError { _private: () })
243 }
244 if time.nanosecond > 999_999_999 {
245 return Err(DatetimeParseError { _private: () })
246 }
247
248 Some(time)
249 } else {
250 offset_allowed = false;
251 None
252 };
253
254 // And finally, parse the offset
255 let offset = if offset_allowed {
256 let next = chars.clone().next();
257 if next == Some('Z') {
258 chars.next();
259 Some(Offset::Z)
260 } else if next.is_none() {
261 None
262 } else {
263 let sign = match next {
264 Some('+') => 1,
265 Some('-') => -1,
266 _ => return Err(DatetimeParseError { _private: () }),
267 };
268 chars.next();
269 let h1 = digit(&mut chars)? as i8;
270 let h2 = digit(&mut chars)? as i8;
271 match chars.next() {
272 Some(':') => {}
273 _ => return Err(DatetimeParseError { _private: () }),
274 }
275 let m1 = digit(&mut chars)?;
276 let m2 = digit(&mut chars)?;
277
278 Some(Offset::Custom {
279 hours: sign * (h1 * 10 + h2),
280 minutes: m1 * 10 + m2,
281 })
282 }
283 } else {
284 None
285 };
286
287 // Return an error if we didn't hit eof, otherwise return our parsed
288 // date
289 if chars.next().is_some() {
290 return Err(DatetimeParseError { _private: () })
291 }
292
293 Ok(Datetime {
294 date: full_date,
295 time: time,
296 offset: offset,
297 })
298 }
299 }
300
301 fn digit(chars: &mut str::Chars) -> Result<u8, DatetimeParseError> {
302 match chars.next() {
303 Some(c) if '0' <= c && c <= '9' => Ok(c as u8 - b'0'),
304 _ => Err(DatetimeParseError { _private: () }),
305 }
306 }
307
308 impl ser::Serialize for Datetime {
309 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
310 where S: ser::Serializer
311 {
312 use serde::ser::SerializeStruct;
313
314 let mut s = serializer.serialize_struct(SERDE_STRUCT_NAME, 1)?;
315 s.serialize_field(SERDE_STRUCT_FIELD_NAME, &self.to_string())?;
316 s.end()
317 }
318 }
319
320 impl<'de> de::Deserialize<'de> for Datetime {
321 fn deserialize<D>(deserializer: D) -> Result<Datetime, D::Error>
322 where D: de::Deserializer<'de>
323 {
324 struct DatetimeVisitor;
325
326 impl<'de> de::Visitor<'de> for DatetimeVisitor {
327 type Value = Datetime;
328
329 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
330 formatter.write_str("a TOML datetime")
331 }
332
333 fn visit_map<V>(self, mut visitor: V) -> Result<Datetime, V::Error>
334 where V: de::MapAccess<'de>
335 {
336 let value = visitor.next_key::<DatetimeKey>()?;
337 if value.is_none() {
338 return Err(de::Error::custom("datetime key not found"))
339 }
340 let v: DatetimeFromString = visitor.next_value()?;
341 Ok(v.value)
342
343 }
344 }
345
346 static FIELDS: [&'static str; 1] = [SERDE_STRUCT_FIELD_NAME];
347 deserializer.deserialize_struct(SERDE_STRUCT_NAME,
348 &FIELDS,
349 DatetimeVisitor)
350 }
351 }
352
353 struct DatetimeKey;
354
355 impl<'de> de::Deserialize<'de> for DatetimeKey {
356 fn deserialize<D>(deserializer: D) -> Result<DatetimeKey, D::Error>
357 where D: de::Deserializer<'de>
358 {
359 struct FieldVisitor;
360
361 impl<'de> de::Visitor<'de> for FieldVisitor {
362 type Value = ();
363
364 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
365 formatter.write_str("a valid datetime field")
366 }
367
368 fn visit_str<E>(self, s: &str) -> Result<(), E>
369 where E: de::Error
370 {
371 if s == SERDE_STRUCT_FIELD_NAME {
372 Ok(())
373 } else {
374 Err(de::Error::custom("expected field with custom name"))
375 }
376 }
377 }
378
379 deserializer.deserialize_identifier(FieldVisitor)?;
380 Ok(DatetimeKey)
381 }
382 }
383
384 pub struct DatetimeFromString {
385 pub value: Datetime,
386 }
387
388 impl<'de> de::Deserialize<'de> for DatetimeFromString {
389 fn deserialize<D>(deserializer: D) -> Result<DatetimeFromString, D::Error>
390 where D: de::Deserializer<'de>
391 {
392 struct Visitor;
393
394 impl<'de> de::Visitor<'de> for Visitor {
395 type Value = DatetimeFromString;
396
397 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
398 formatter.write_str("string containing a datetime")
399 }
400
401 fn visit_str<E>(self, s: &str) -> Result<DatetimeFromString, E>
402 where E: de::Error,
403 {
404 match s.parse() {
405 Ok(date) => Ok(DatetimeFromString { value: date }),
406 Err(e) => Err(de::Error::custom(e)),
407 }
408 }
409 }
410
411 deserializer.deserialize_str(Visitor)
412 }
413 }
414
415 impl fmt::Display for DatetimeParseError {
416 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
417 "failed to parse datetime".fmt(f)
418 }
419 }
420
421 impl error::Error for DatetimeParseError {
422 fn description(&self) -> &str {
423 "failed to parse datetime"
424 }
425 }