]> git.proxmox.com Git - rustc.git/blob - vendor/time-macros/src/date.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / time-macros / src / date.rs
1 use std::iter::Peekable;
2
3 use proc_macro::{token_stream, TokenTree};
4 use time_core::util::{days_in_year, weeks_in_year};
5
6 use crate::helpers::{
7 consume_any_ident, consume_number, consume_punct, days_in_year_month, ymd_to_yo, ywd_to_yo,
8 };
9 use crate::to_tokens::ToTokenTree;
10 use crate::Error;
11
12 #[cfg(feature = "large-dates")]
13 const MAX_YEAR: i32 = 999_999;
14 #[cfg(not(feature = "large-dates"))]
15 const MAX_YEAR: i32 = 9_999;
16
17 pub(crate) struct Date {
18 pub(crate) year: i32,
19 pub(crate) ordinal: u16,
20 }
21
22 pub(crate) fn parse(chars: &mut Peekable<token_stream::IntoIter>) -> Result<Date, Error> {
23 let (year_sign_span, year_sign, explicit_sign) = if let Ok(span) = consume_punct('-', chars) {
24 (Some(span), -1, true)
25 } else if let Ok(span) = consume_punct('+', chars) {
26 (Some(span), 1, true)
27 } else {
28 (None, 1, false)
29 };
30 let (year_span, mut year) = consume_number::<i32>("year", chars)?;
31 year *= year_sign;
32 if year.abs() > MAX_YEAR {
33 return Err(Error::InvalidComponent {
34 name: "year",
35 value: year.to_string(),
36 span_start: Some(year_sign_span.unwrap_or(year_span)),
37 span_end: Some(year_span),
38 });
39 }
40 if !explicit_sign && year.abs() >= 10_000 {
41 return Err(Error::Custom {
42 message: "years with more than four digits must have an explicit sign".into(),
43 span_start: Some(year_sign_span.unwrap_or(year_span)),
44 span_end: Some(year_span),
45 });
46 }
47
48 consume_punct('-', chars)?;
49
50 // year-week-day
51 if let Ok(w_span) = consume_any_ident(&["W"], chars) {
52 let (week_span, week) = consume_number::<u8>("week", chars)?;
53 consume_punct('-', chars)?;
54 let (day_span, day) = consume_number::<u8>("day", chars)?;
55
56 if week > weeks_in_year(year) {
57 return Err(Error::InvalidComponent {
58 name: "week",
59 value: week.to_string(),
60 span_start: Some(w_span),
61 span_end: Some(week_span),
62 });
63 }
64 if day == 0 || day > 7 {
65 return Err(Error::InvalidComponent {
66 name: "day",
67 value: day.to_string(),
68 span_start: Some(day_span),
69 span_end: Some(day_span),
70 });
71 }
72
73 let (year, ordinal) = ywd_to_yo(year, week, day);
74
75 return Ok(Date { year, ordinal });
76 }
77
78 // We don't yet know whether it's year-month-day or year-ordinal.
79 let (month_or_ordinal_span, month_or_ordinal) =
80 consume_number::<u16>("month or ordinal", chars)?;
81
82 // year-month-day
83 #[allow(clippy::branches_sharing_code)] // clarity
84 if consume_punct('-', chars).is_ok() {
85 let (month_span, month) = (month_or_ordinal_span, month_or_ordinal);
86 let (day_span, day) = consume_number::<u8>("day", chars)?;
87
88 if month == 0 || month > 12 {
89 return Err(Error::InvalidComponent {
90 name: "month",
91 value: month.to_string(),
92 span_start: Some(month_span),
93 span_end: Some(month_span),
94 });
95 }
96 let month = month as _;
97 if day == 0 || day > days_in_year_month(year, month) {
98 return Err(Error::InvalidComponent {
99 name: "day",
100 value: day.to_string(),
101 span_start: Some(day_span),
102 span_end: Some(day_span),
103 });
104 }
105
106 let (year, ordinal) = ymd_to_yo(year, month, day);
107
108 Ok(Date { year, ordinal })
109 }
110 // year-ordinal
111 else {
112 let (ordinal_span, ordinal) = (month_or_ordinal_span, month_or_ordinal);
113
114 if ordinal == 0 || ordinal > days_in_year(year) {
115 return Err(Error::InvalidComponent {
116 name: "ordinal",
117 value: ordinal.to_string(),
118 span_start: Some(ordinal_span),
119 span_end: Some(ordinal_span),
120 });
121 }
122
123 Ok(Date { year, ordinal })
124 }
125 }
126
127 impl ToTokenTree for Date {
128 fn into_token_tree(self) -> TokenTree {
129 quote_group! {{
130 const DATE: ::time::Date = unsafe {
131 ::time::Date::__from_ordinal_date_unchecked(
132 #(self.year),
133 #(self.ordinal),
134 )
135 };
136 DATE
137 }}
138 }
139 }