diff options
Diffstat (limited to 'vendor/time-macros/src/helpers/mod.rs')
-rw-r--r-- | vendor/time-macros/src/helpers/mod.rs | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/vendor/time-macros/src/helpers/mod.rs b/vendor/time-macros/src/helpers/mod.rs new file mode 100644 index 0000000..56300b3 --- /dev/null +++ b/vendor/time-macros/src/helpers/mod.rs @@ -0,0 +1,127 @@ +#[cfg(any(feature = "formatting", feature = "parsing"))] +mod string; + +use std::iter::Peekable; +use std::str::FromStr; + +use proc_macro::{token_stream, Span, TokenTree}; +use time_core::util::{days_in_year, is_leap_year}; + +use crate::Error; + +#[cfg(any(feature = "formatting", feature = "parsing"))] +pub(crate) fn get_string_literal( + mut tokens: impl Iterator<Item = TokenTree>, +) -> Result<(Span, Vec<u8>), Error> { + match (tokens.next(), tokens.next()) { + (Some(TokenTree::Literal(literal)), None) => string::parse(&literal), + (Some(tree), None) => Err(Error::ExpectedString { + span_start: Some(tree.span()), + span_end: Some(tree.span()), + }), + (_, Some(tree)) => Err(Error::UnexpectedToken { tree }), + (None, None) => Err(Error::ExpectedString { + span_start: None, + span_end: None, + }), + } +} + +pub(crate) fn consume_number<T: FromStr>( + component_name: &'static str, + chars: &mut Peekable<token_stream::IntoIter>, +) -> Result<(Span, T), Error> { + let (span, digits) = match chars.next() { + Some(TokenTree::Literal(literal)) => (literal.span(), literal.to_string()), + Some(tree) => return Err(Error::UnexpectedToken { tree }), + None => return Err(Error::UnexpectedEndOfInput), + }; + + if let Ok(value) = digits.replace('_', "").parse() { + Ok((span, value)) + } else { + Err(Error::InvalidComponent { + name: component_name, + value: digits, + span_start: Some(span), + span_end: Some(span), + }) + } +} + +pub(crate) fn consume_any_ident( + idents: &[&str], + chars: &mut Peekable<token_stream::IntoIter>, +) -> Result<Span, Error> { + match chars.peek() { + Some(TokenTree::Ident(char)) if idents.contains(&char.to_string().as_str()) => { + let ret = Ok(char.span()); + drop(chars.next()); + ret + } + Some(tree) => Err(Error::UnexpectedToken { tree: tree.clone() }), + None => Err(Error::UnexpectedEndOfInput), + } +} + +pub(crate) fn consume_punct( + c: char, + chars: &mut Peekable<token_stream::IntoIter>, +) -> Result<Span, Error> { + match chars.peek() { + Some(TokenTree::Punct(punct)) if *punct == c => { + let ret = Ok(punct.span()); + drop(chars.next()); + ret + } + Some(tree) => Err(Error::UnexpectedToken { tree: tree.clone() }), + None => Err(Error::UnexpectedEndOfInput), + } +} + +fn jan_weekday(year: i32, ordinal: i32) -> u8 { + macro_rules! div_floor { + ($a:expr, $b:expr) => {{ + let (_quotient, _remainder) = ($a / $b, $a % $b); + if (_remainder > 0 && $b < 0) || (_remainder < 0 && $b > 0) { + _quotient - 1 + } else { + _quotient + } + }}; + } + + let adj_year = year - 1; + ((ordinal + adj_year + div_floor!(adj_year, 4) - div_floor!(adj_year, 100) + + div_floor!(adj_year, 400) + + 6) + .rem_euclid(7)) as _ +} + +pub(crate) fn days_in_year_month(year: i32, month: u8) -> u8 { + [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month as usize - 1] + + (month == 2 && is_leap_year(year)) as u8 +} + +pub(crate) fn ywd_to_yo(year: i32, week: u8, iso_weekday_number: u8) -> (i32, u16) { + let (ordinal, overflow) = (u16::from(week) * 7 + u16::from(iso_weekday_number)) + .overflowing_sub(u16::from(jan_weekday(year, 4)) + 4); + + if overflow || ordinal == 0 { + return (year - 1, (ordinal.wrapping_add(days_in_year(year - 1)))); + } + + let days_in_cur_year = days_in_year(year); + if ordinal > days_in_cur_year { + (year + 1, ordinal - days_in_cur_year) + } else { + (year, ordinal) + } +} + +pub(crate) fn ymd_to_yo(year: i32, month: u8, day: u8) -> (i32, u16) { + let ordinal = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334][month as usize - 1] + + (month > 2 && is_leap_year(year)) as u16; + + (year, ordinal + u16::from(day)) +} |