]> git.proxmox.com Git - rustc.git/blame - src/vendor/toml-0.3.2/src/datetime.rs
New upstream version 1.19.0+dfsg3
[rustc.git] / src / vendor / toml-0.3.2 / src / datetime.rs
CommitLineData
7cac9316
XL
1use std::fmt;
2use std::str::{self, FromStr};
3use std::error;
4
5use 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)]
25pub 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)]
33pub 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.
43pub const SERDE_STRUCT_FIELD_NAME: &'static str = "$__toml_private_datetime";
44pub const SERDE_STRUCT_NAME: &'static str = "$__toml_private_Datetime";
45
46#[derive(PartialEq, Clone)]
47struct Date {
48 year: u16,
49 month: u8,
50 day: u8,
51}
52
53#[derive(PartialEq, Clone)]
54struct Time {
55 hour: u8,
56 minute: u8,
57 second: u8,
58 secfract: Option<f64>,
59}
60
61#[derive(PartialEq, Clone)]
62enum Offset {
63 Z,
64 Custom { hours: i8, minutes: u8 },
65}
66
67impl fmt::Debug for Datetime {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 fmt::Display::fmt(self, f)
70 }
71}
72
73impl 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
91impl 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
97impl 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 let Some(i) = self.secfract {
101 let s = format!("{}", i);
102 write!(f, "{}", s.trim_left_matches("0"))?;
103 }
104 Ok(())
105 }
106}
107
108impl 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
119impl 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 if full_date.is_none() {
183 true
184 } else {
185 false
186 };
187 let time = if partial_time {
188 let h1 = digit(&mut chars)?;
189 let h2 = digit(&mut chars)?;
190 match chars.next() {
191 Some(':') => {}
192 _ => return Err(DatetimeParseError { _private: () }),
193 }
194 let m1 = digit(&mut chars)?;
195 let m2 = digit(&mut chars)?;
196 match chars.next() {
197 Some(':') => {}
198 _ => return Err(DatetimeParseError { _private: () }),
199 }
200 let s1 = digit(&mut chars)?;
201 let s2 = digit(&mut chars)?;
202
203 let secfract = if chars.clone().next() == Some('.') {
204 chars.next();
205 let mut first = true;
206 let whole = chars.as_str();
207 let mut end = whole.len();
208 for (i, c) in whole.char_indices() {
209 match c {
210 '0' ... '9' => {}
211 _ => {
212 end = i;
213 break
214 }
215 }
216 first = false;
217 }
218 if first {
219 return Err(DatetimeParseError { _private: () })
220 }
221 chars = whole[end..].chars();
222 match format!("0.{}", &whole[..end]).parse() {
223 Ok(f) => Some(f),
224 Err(_) => return Err(DatetimeParseError { _private: () }),
225 }
226 } else {
227 None
228 };
229
230 let time = Time {
231 hour: h1 * 10 + h2,
232 minute: m1 * 10 + m2,
233 second: s1 * 10 + s2,
234 secfract: secfract,
235 };
236
237 if time.hour > 24 {
238 return Err(DatetimeParseError { _private: () })
239 }
240 if time.minute > 59 {
241 return Err(DatetimeParseError { _private: () })
242 }
243 if time.second > 60 {
244 return Err(DatetimeParseError { _private: () })
245 }
246
247 Some(time)
248 } else {
249 offset_allowed = false;
250 None
251 };
252
253 // And finally, parse the offset
254 let offset = if offset_allowed {
255 let next = chars.clone().next();
256 if next == Some('Z') {
257 chars.next();
258 Some(Offset::Z)
259 } else if next.is_none() {
260 None
261 } else {
262 let sign = match next {
263 Some('+') => 1,
264 Some('-') => -1,
265 _ => return Err(DatetimeParseError { _private: () }),
266 };
267 chars.next();
268 let h1 = digit(&mut chars)? as i8;
269 let h2 = digit(&mut chars)? as i8;
270 match chars.next() {
271 Some(':') => {}
272 _ => return Err(DatetimeParseError { _private: () }),
273 }
274 let m1 = digit(&mut chars)?;
275 let m2 = digit(&mut chars)?;
276
277 Some(Offset::Custom {
278 hours: sign * (h1 * 10 + h2),
279 minutes: m1 * 10 + m2,
280 })
281 }
282 } else {
283 None
284 };
285
286 // Return an error if we didn't hit eof, otherwise return our parsed
287 // date
288 if chars.next().is_some() {
289 return Err(DatetimeParseError { _private: () })
290 }
291
292 Ok(Datetime {
293 date: full_date,
294 time: time,
295 offset: offset,
296 })
297 }
298}
299
300fn digit(chars: &mut str::Chars) -> Result<u8, DatetimeParseError> {
301 match chars.next() {
302 Some(c) if '0' <= c && c <= '9' => Ok(c as u8 - '0' as u8),
303 _ => Err(DatetimeParseError { _private: () }),
304 }
305}
306
307impl ser::Serialize for Datetime {
308 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
309 where S: ser::Serializer
310 {
311 use serde::ser::SerializeStruct;
312
313 let mut s = serializer.serialize_struct(SERDE_STRUCT_NAME, 1)?;
314 s.serialize_field(SERDE_STRUCT_FIELD_NAME, &self.to_string())?;
315 s.end()
316 }
317}
318
319impl de::Deserialize for Datetime {
320 fn deserialize<D>(deserializer: D) -> Result<Datetime, D::Error>
321 where D: de::Deserializer
322 {
323 struct DatetimeVisitor;
324
325 impl de::Visitor for DatetimeVisitor {
326 type Value = Datetime;
327
328 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
329 formatter.write_str("a TOML datetime")
330 }
331
332 fn visit_map<V>(self, mut visitor: V) -> Result<Datetime, V::Error>
333 where V: de::MapVisitor
334 {
335 let value = visitor.visit_key::<DatetimeKey>()?;
336 if value.is_none() {
337 return Err(de::Error::custom("datetime key not found"))
338 }
339 let v: DatetimeFromString = visitor.visit_value()?;
340 Ok(v.value)
341
342 }
343 }
344
345 static FIELDS: [&'static str; 1] = [SERDE_STRUCT_FIELD_NAME];
346 deserializer.deserialize_struct(SERDE_STRUCT_NAME,
347 &FIELDS,
348 DatetimeVisitor)
349 }
350}
351
352struct DatetimeKey;
353
354impl de::Deserialize for DatetimeKey {
355 fn deserialize<D>(deserializer: D) -> Result<DatetimeKey, D::Error>
356 where D: de::Deserializer
357 {
358 struct FieldVisitor;
359
360 impl de::Visitor for FieldVisitor {
361 type Value = ();
362
363 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
364 formatter.write_str("a valid datetime field")
365 }
366
367 fn visit_str<E>(self, s: &str) -> Result<(), E>
368 where E: de::Error
369 {
370 if s == SERDE_STRUCT_FIELD_NAME {
371 Ok(())
372 } else {
373 Err(de::Error::custom("expected field with custom name"))
374 }
375 }
376 }
377
378 deserializer.deserialize_struct_field(FieldVisitor)?;
379 Ok(DatetimeKey)
380 }
381}
382
383pub struct DatetimeFromString {
384 pub value: Datetime,
385}
386
387impl de::Deserialize for DatetimeFromString {
388 fn deserialize<D>(deserializer: D) -> Result<DatetimeFromString, D::Error>
389 where D: de::Deserializer
390 {
391 struct Visitor;
392
393 impl de::Visitor for Visitor {
394 type Value = DatetimeFromString;
395
396 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
397 formatter.write_str("string containing a datetime")
398 }
399
400 fn visit_str<E>(self, s: &str) -> Result<DatetimeFromString, E>
401 where E: de::Error,
402 {
403 match s.parse() {
404 Ok(date) => Ok(DatetimeFromString { value: date }),
405 Err(e) => Err(de::Error::custom(e)),
406 }
407 }
408 }
409
410 deserializer.deserialize_str(Visitor)
411 }
412}
413
414impl fmt::Display for DatetimeParseError {
415 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
416 "failed to parse datetime".fmt(f)
417 }
418}
419
420impl error::Error for DatetimeParseError {
421 fn description(&self) -> &str {
422 "failed to parse datetime"
423 }
424}