diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
commit | 218caa410aa38c29984be31a5229b9fa717560ee (patch) | |
tree | c54bd55eeb6e4c508940a30e94c0032fbd45d677 /vendor/time-macros/src/helpers | |
parent | Releasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/time-macros/src/helpers')
-rw-r--r-- | vendor/time-macros/src/helpers/mod.rs | 129 | ||||
-rw-r--r-- | vendor/time-macros/src/helpers/string.rs | 188 |
2 files changed, 317 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 000000000..cbf3ba3ed --- /dev/null +++ b/vendor/time-macros/src/helpers/mod.rs @@ -0,0 +1,129 @@ +#[cfg(any(feature = "formatting", feature = "parsing"))] +mod string; + +use std::iter::Peekable; +use std::str::FromStr; + +#[cfg(any(feature = "formatting", feature = "parsing"))] +use proc_macro::TokenStream; +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(tokens: TokenStream) -> Result<(Span, Vec<u8>), Error> { + let mut tokens = tokens.into_iter(); + + 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)) +} diff --git a/vendor/time-macros/src/helpers/string.rs b/vendor/time-macros/src/helpers/string.rs new file mode 100644 index 000000000..fa3780f5e --- /dev/null +++ b/vendor/time-macros/src/helpers/string.rs @@ -0,0 +1,188 @@ +use std::ops::{Index, RangeFrom}; + +use proc_macro::Span; + +use crate::Error; + +pub(crate) fn parse(token: &proc_macro::Literal) -> Result<(Span, Vec<u8>), Error> { + let span = token.span(); + let repr = token.to_string(); + + match repr.as_bytes() { + [b'"', ..] => Ok((span, parse_lit_str_cooked(&repr[1..]))), + [b'b', b'"', rest @ ..] => Ok((span, parse_lit_byte_str_cooked(rest))), + [b'r', rest @ ..] | [b'b', b'r', rest @ ..] => Ok((span, parse_lit_str_raw(rest))), + _ => Err(Error::ExpectedString { + span_start: Some(span), + span_end: Some(span), + }), + } +} + +fn byte(s: impl AsRef<[u8]>, idx: usize) -> u8 { + s.as_ref().get(idx).copied().unwrap_or_default() +} + +fn parse_lit_str_cooked(mut s: &str) -> Vec<u8> { + let mut content = String::new(); + 'outer: loop { + let ch = match byte(s, 0) { + b'"' => break, + b'\\' => { + let b = byte(s, 1); + s = &s[2..]; + match b { + b'x' => { + let (byte, rest) = backslash_x(s); + s = rest; + char::from_u32(u32::from(byte)).expect("byte was just validated") + } + b'u' => { + let (chr, rest) = backslash_u(s); + s = rest; + chr + } + b'n' => '\n', + b'r' => '\r', + b't' => '\t', + b'\\' => '\\', + b'0' => '\0', + b'\'' => '\'', + b'"' => '"', + b'\r' | b'\n' => loop { + let ch = s.chars().next().unwrap_or_default(); + if ch.is_whitespace() { + s = &s[ch.len_utf8()..]; + } else { + continue 'outer; + } + }, + _ => unreachable!("invalid escape"), + } + } + b'\r' => { + // bare CR not permitted + s = &s[2..]; + '\n' + } + _ => { + let ch = s.chars().next().unwrap_or_default(); + s = &s[ch.len_utf8()..]; + ch + } + }; + content.push(ch); + } + + content.into_bytes() +} + +fn parse_lit_str_raw(s: &[u8]) -> Vec<u8> { + let mut pounds = 0; + while byte(s, pounds) == b'#' { + pounds += 1; + } + let close = s + .iter() + .rposition(|&b| b == b'"') + .expect("had a string without trailing \""); + + s[pounds + 1..close].to_owned() +} + +fn parse_lit_byte_str_cooked(mut v: &[u8]) -> Vec<u8> { + let mut out = Vec::new(); + 'outer: loop { + let byte = match byte(v, 0) { + b'"' => break, + b'\\' => { + let b = byte(v, 1); + v = &v[2..]; + match b { + b'x' => { + let (byte, rest) = backslash_x(v); + v = rest; + byte + } + b'n' => b'\n', + b'r' => b'\r', + b't' => b'\t', + b'\\' => b'\\', + b'0' => b'\0', + b'\'' => b'\'', + b'"' => b'"', + b'\r' | b'\n' => loop { + let byte = byte(v, 0); + let ch = char::from_u32(u32::from(byte)).expect("invalid byte"); + if ch.is_whitespace() { + v = &v[1..]; + } else { + continue 'outer; + } + }, + _ => unreachable!("invalid escape"), + } + } + b'\r' => { + // bare CR not permitted + v = &v[2..]; + b'\n' + } + b => { + v = &v[1..]; + b + } + }; + out.push(byte); + } + + out +} + +fn backslash_x<S>(s: &S) -> (u8, &S) +where + S: Index<RangeFrom<usize>, Output = S> + AsRef<[u8]> + ?Sized, +{ + let mut ch = 0; + let b0 = byte(s, 0); + let b1 = byte(s, 1); + ch += 0x10 * (b0 - b'0'); + ch += match b1 { + b'0'..=b'9' => b1 - b'0', + b'a'..=b'f' => 10 + (b1 - b'a'), + b'A'..=b'F' => 10 + (b1 - b'A'), + _ => unreachable!("invalid hex escape"), + }; + (ch, &s[2..]) +} + +fn backslash_u(mut s: &str) -> (char, &str) { + s = &s[1..]; + + let mut ch = 0; + let mut digits = 0; + loop { + let b = byte(s, 0); + let digit = match b { + b'0'..=b'9' => b - b'0', + b'a'..=b'f' => 10 + b - b'a', + b'A'..=b'F' => 10 + b - b'A', + b'_' if digits > 0 => { + s = &s[1..]; + continue; + } + b'}' if digits != 0 => break, + _ => unreachable!("invalid unicode escape"), + }; + ch *= 0x10; + ch += u32::from(digit); + digits += 1; + s = &s[1..]; + } + s = &s[1..]; + + ( + char::from_u32(ch).expect("invalid unicode escape passed by compiler"), + s, + ) +} |