1 | #[cfg (any(feature = "formatting" , feature = "parsing" ))] |
2 | mod string; |
3 | |
4 | use std::iter::Peekable; |
5 | use std::str::FromStr; |
6 | |
7 | use num_conv::prelude::*; |
8 | use proc_macro::{token_stream, Span, TokenTree}; |
9 | use time_core::util::{days_in_year, is_leap_year}; |
10 | |
11 | use crate::Error; |
12 | |
13 | #[cfg (any(feature = "formatting" , feature = "parsing" ))] |
14 | pub(crate) fn get_string_literal( |
15 | mut tokens: impl Iterator<Item = TokenTree>, |
16 | ) -> Result<(Span, Vec<u8>), Error> { |
17 | match (tokens.next(), tokens.next()) { |
18 | (Some(TokenTree::Literal(literal: Literal)), None) => string::parse(&literal), |
19 | (Some(tree: TokenTree), None) => Err(Error::ExpectedString { |
20 | span_start: Some(tree.span()), |
21 | span_end: Some(tree.span()), |
22 | }), |
23 | (_, Some(tree: TokenTree)) => Err(Error::UnexpectedToken { tree }), |
24 | (None, None) => Err(Error::ExpectedString { |
25 | span_start: None, |
26 | span_end: None, |
27 | }), |
28 | } |
29 | } |
30 | |
31 | pub(crate) fn consume_number<T: FromStr>( |
32 | component_name: &'static str, |
33 | chars: &mut Peekable<token_stream::IntoIter>, |
34 | ) -> Result<(Span, T), Error> { |
35 | let (span: Span, digits: String) = match chars.next() { |
36 | Some(TokenTree::Literal(literal: Literal)) => (literal.span(), literal.to_string()), |
37 | Some(tree: TokenTree) => return Err(Error::UnexpectedToken { tree }), |
38 | None => return Err(Error::UnexpectedEndOfInput), |
39 | }; |
40 | |
41 | if let Ok(value: T) = digits.replace(from:'_' , to:"" ).parse() { |
42 | Ok((span, value)) |
43 | } else { |
44 | Err(Error::InvalidComponent { |
45 | name: component_name, |
46 | value: digits, |
47 | span_start: Some(span), |
48 | span_end: Some(span), |
49 | }) |
50 | } |
51 | } |
52 | |
53 | pub(crate) fn consume_any_ident( |
54 | idents: &[&str], |
55 | chars: &mut Peekable<token_stream::IntoIter>, |
56 | ) -> Result<Span, Error> { |
57 | match chars.peek() { |
58 | Some(TokenTree::Ident(char: &Ident)) if idents.contains(&char.to_string().as_str()) => { |
59 | let ret: Result = Ok(char.span()); |
60 | drop(chars.next()); |
61 | ret |
62 | } |
63 | Some(tree: &TokenTree) => Err(Error::UnexpectedToken { tree: tree.clone() }), |
64 | None => Err(Error::UnexpectedEndOfInput), |
65 | } |
66 | } |
67 | |
68 | pub(crate) fn consume_punct( |
69 | c: char, |
70 | chars: &mut Peekable<token_stream::IntoIter>, |
71 | ) -> Result<Span, Error> { |
72 | match chars.peek() { |
73 | Some(TokenTree::Punct(punct: &Punct)) if *punct == c => { |
74 | let ret: Result = Ok(punct.span()); |
75 | drop(chars.next()); |
76 | ret |
77 | } |
78 | Some(tree: &TokenTree) => Err(Error::UnexpectedToken { tree: tree.clone() }), |
79 | None => Err(Error::UnexpectedEndOfInput), |
80 | } |
81 | } |
82 | |
83 | fn jan_weekday(year: i32, ordinal: i32) -> u8 { |
84 | macro_rules! div_floor { |
85 | ($a:expr, $b:expr) => {{ |
86 | let (_quotient, _remainder) = ($a / $b, $a % $b); |
87 | if (_remainder > 0 && $b < 0) || (_remainder < 0 && $b > 0) { |
88 | _quotient - 1 |
89 | } else { |
90 | _quotient |
91 | } |
92 | }}; |
93 | } |
94 | |
95 | let adj_year: i32 = year - 1; |
96 | (ordinal + adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100) |
97 | + div_floor!(adj_year, 400) |
98 | + 6) |
99 | .rem_euclid(7) |
100 | .cast_unsigned() |
101 | .truncate() |
102 | } |
103 | |
104 | pub(crate) fn days_in_year_month(year: i32, month: u8) -> u8 { |
105 | [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month.extend::<usize>() - 1] |
106 | + u8::from(month == 2 && is_leap_year(year)) |
107 | } |
108 | |
109 | pub(crate) fn ywd_to_yo(year: i32, week: u8, iso_weekday_number: u8) -> (i32, u16) { |
110 | let (ordinal: u16, overflow: bool) = (u16::from(week) * 7 + u16::from(iso_weekday_number)) |
111 | .overflowing_sub(u16::from(jan_weekday(year, ordinal:4)) + 4); |
112 | |
113 | if overflow || ordinal == 0 { |
114 | return (year - 1, (ordinal.wrapping_add(days_in_year(year - 1)))); |
115 | } |
116 | |
117 | let days_in_cur_year: u16 = days_in_year(year); |
118 | if ordinal > days_in_cur_year { |
119 | (year + 1, ordinal - days_in_cur_year) |
120 | } else { |
121 | (year, ordinal) |
122 | } |
123 | } |
124 | |
125 | pub(crate) fn ymd_to_yo(year: i32, month: u8, day: u8) -> (i32, u16) { |
126 | let ordinal: u16 = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] |
127 | [month.extend::<usize>() - 1] |
128 | + u16::from(month > 2 && is_leap_year(year)); |
129 | |
130 | (year, ordinal + u16::from(day)) |
131 | } |
132 | |