From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 5E09A8287A for ; Tue, 30 Nov 2021 13:13:13 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id A449C26A44 for ; Tue, 30 Nov 2021 13:12:21 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 5B64126949 for ; Tue, 30 Nov 2021 13:12:13 +0100 (CET) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 35A1C44689 for ; Tue, 30 Nov 2021 13:12:13 +0100 (CET) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Tue, 30 Nov 2021 13:12:03 +0100 Message-Id: <20211130121209.216846-10-d.csapak@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20211130121209.216846-1-d.csapak@proxmox.com> References: <20211130121209.216846-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.183 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [lib.rs, time.rs] Subject: [pbs-devel] [PATCH proxmox 09/14] proxmox-time: move TimeSpan into time_span.rs X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 30 Nov 2021 12:13:13 -0000 and related parsing functions Signed-off-by: Dominik Csapak --- proxmox-time/src/lib.rs | 6 +- proxmox-time/src/parse_time.rs | 157 ------------------- proxmox-time/src/time.rs | 129 +--------------- proxmox-time/src/time_span.rs | 265 +++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+), 288 deletions(-) delete mode 100644 proxmox-time/src/parse_time.rs create mode 100644 proxmox-time/src/time_span.rs diff --git a/proxmox-time/src/lib.rs b/proxmox-time/src/lib.rs index 0436628..cbb7008 100644 --- a/proxmox-time/src/lib.rs +++ b/proxmox-time/src/lib.rs @@ -7,9 +7,6 @@ use anyhow::{bail, format_err, Error}; mod tm_editor; pub use tm_editor::*; -mod parse_time; -pub use parse_time::*; - mod time; pub use time::*; @@ -20,6 +17,9 @@ pub(crate) mod date_time_value; mod calendar_event; pub use calendar_event::*; +mod time_span; +pub use time_span::*; + mod week_days; pub use week_days::*; diff --git a/proxmox-time/src/parse_time.rs b/proxmox-time/src/parse_time.rs deleted file mode 100644 index 51c0486..0000000 --- a/proxmox-time/src/parse_time.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::collections::HashMap; - -use anyhow::{bail, Error}; -use lazy_static::lazy_static; - -use super::time::*; -use super::daily_duration::*; - -use nom::{ - error::{context, ParseError, VerboseError}, - bytes::complete::{tag, take_while1}, - combinator::{map_res, all_consuming, opt, recognize}, - sequence::{pair, preceded, terminated, tuple}, - character::complete::{alpha1, space0, digit1}, - multi::separated_nonempty_list, -}; - -use crate::parse_helpers::{parse_complete_line, parse_error, parse_hm_time, parse_time_comp, parse_u64, IResult}; -use crate::{parse_weekdays_range, WeekDays}; -use crate::date_time_value::DateTimeValue; - -lazy_static! { - static ref TIME_SPAN_UNITS: HashMap<&'static str, f64> = { - let mut map = HashMap::new(); - - let second = 1.0; - - map.insert("seconds", second); - map.insert("second", second); - map.insert("sec", second); - map.insert("s", second); - - let msec = second / 1000.0; - - map.insert("msec", msec); - map.insert("ms", msec); - - let usec = msec / 1000.0; - - map.insert("usec", usec); - map.insert("us", usec); - map.insert("µs", usec); - - let nsec = usec / 1000.0; - - map.insert("nsec", nsec); - map.insert("ns", nsec); - - let minute = second * 60.0; - - map.insert("minutes", minute); - map.insert("minute", minute); - map.insert("min", minute); - map.insert("m", minute); - - let hour = minute * 60.0; - - map.insert("hours", hour); - map.insert("hour", hour); - map.insert("hr", hour); - map.insert("h", hour); - - let day = hour * 24.0 ; - - map.insert("days", day); - map.insert("day", day); - map.insert("d", day); - - let week = day * 7.0; - - map.insert("weeks", week); - map.insert("week", week); - map.insert("w", week); - - let month = 30.44 * day; - - map.insert("months", month); - map.insert("month", month); - map.insert("M", month); - - let year = 365.25 * day; - - map.insert("years", year); - map.insert("year", year); - map.insert("y", year); - - map - }; -} - -fn parse_time_unit(i: &str) -> IResult<&str, &str> { - let (n, text) = take_while1(|c: char| char::is_ascii_alphabetic(&c) || c == 'µ')(i)?; - if TIME_SPAN_UNITS.contains_key(&text) { - Ok((n, text)) - } else { - Err(parse_error(text, "time unit")) - } -} - - -/// Parse a [TimeSpan] -pub fn parse_time_span(i: &str) -> Result { - parse_complete_line("time span", i, parse_time_span_incomplete) -} - -fn parse_time_span_incomplete(mut i: &str) -> IResult<&str, TimeSpan> { - - let mut ts = TimeSpan::default(); - - loop { - i = space0(i)?.0; - if i.is_empty() { break; } - let (n, num) = parse_u64(i)?; - i = space0(n)?.0; - - if let (n, Some(unit)) = opt(parse_time_unit)(i)? { - i = n; - match unit { - "seconds" | "second" | "sec" | "s" => { - ts.seconds += num; - } - "msec" | "ms" => { - ts.msec += num; - } - "usec" | "us" | "µs" => { - ts.usec += num; - } - "nsec" | "ns" => { - ts.nsec += num; - } - "minutes" | "minute" | "min" | "m" => { - ts.minutes += num; - } - "hours" | "hour" | "hr" | "h" => { - ts.hours += num; - } - "days" | "day" | "d" => { - ts.days += num; - } - "weeks" | "week" | "w" => { - ts.weeks += num; - } - "months" | "month" | "M" => { - ts.months += num; - } - "years" | "year" | "y" => { - ts.years += num; - } - _ => return Err(parse_error(unit, "internal error")), - } - } else { - ts.seconds += num; - } - } - - Ok((i, ts)) -} diff --git a/proxmox-time/src/time.rs b/proxmox-time/src/time.rs index 1c45a09..ac2f510 100644 --- a/proxmox-time/src/time.rs +++ b/proxmox-time/src/time.rs @@ -1,136 +1,9 @@ -use anyhow::Error; - -use crate::date_time_value::DateTimeValue; -use crate::TmEditor; -use crate::WeekDays; - -use crate::{compute_next_event, parse_calendar_event, parse_time_span}; - -/// A time spans defines a time duration -#[derive(Default, Clone, Debug)] -pub struct TimeSpan { - pub nsec: u64, - pub usec: u64, - pub msec: u64, - pub seconds: u64, - pub minutes: u64, - pub hours: u64, - pub days: u64, - pub weeks: u64, - pub months: u64, - pub years: u64, -} - -impl From for f64 { - fn from(ts: TimeSpan) -> Self { - (ts.seconds as f64) + - ((ts.nsec as f64) / 1_000_000_000.0) + - ((ts.usec as f64) / 1_000_000.0) + - ((ts.msec as f64) / 1_000.0) + - ((ts.minutes as f64) * 60.0) + - ((ts.hours as f64) * 3600.0) + - ((ts.days as f64) * 3600.0 * 24.0) + - ((ts.weeks as f64) * 3600.0 * 24.0 * 7.0) + - ((ts.months as f64) * 3600.0 * 24.0 * 30.44) + - ((ts.years as f64) * 3600.0 * 24.0 * 365.25) - } -} - -impl From for TimeSpan { - fn from(duration: std::time::Duration) -> Self { - let mut duration = duration.as_nanos(); - let nsec = (duration % 1000) as u64; - duration /= 1000; - let usec = (duration % 1000) as u64; - duration /= 1000; - let msec = (duration % 1000) as u64; - duration /= 1000; - let seconds = (duration % 60) as u64; - duration /= 60; - let minutes = (duration % 60) as u64; - duration /= 60; - let hours = (duration % 24) as u64; - duration /= 24; - let years = (duration as f64 / 365.25) as u64; - let ydays = (duration as f64 % 365.25) as u64; - let months = (ydays as f64 / 30.44) as u64; - let mdays = (ydays as f64 % 30.44) as u64; - let weeks = mdays / 7; - let days = mdays % 7; - Self { - nsec, - usec, - msec, - seconds, - minutes, - hours, - days, - weeks, - months, - years, - } - } -} - -impl std::fmt::Display for TimeSpan { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - let mut first = true; - { // block scope for mutable borrows - let mut do_write = |v: u64, unit: &str| -> Result<(), std::fmt::Error> { - if !first { - write!(f, " ")?; - } - first = false; - write!(f, "{}{}", v, unit) - }; - if self.years > 0 { - do_write(self.years, "y")?; - } - if self.months > 0 { - do_write(self.months, "m")?; - } - if self.weeks > 0 { - do_write(self.weeks, "w")?; - } - if self.days > 0 { - do_write(self.days, "d")?; - } - if self.hours > 0 { - do_write(self.hours, "h")?; - } - if self.minutes > 0 { - do_write(self.minutes, "min")?; - } - } - if !first { - write!(f, " ")?; - } - let seconds = self.seconds as f64 + (self.msec as f64 / 1000.0); - if seconds >= 0.1 { - if seconds >= 1.0 || !first { - write!(f, "{:.0}s", seconds)?; - } else { - write!(f, "{:.1}s", seconds)?; - } - } else if first { - write!(f, "<0.1s")?; - } - Ok(()) - } -} - -/// Verify the format of the [TimeSpan] -pub fn verify_time_span(i: &str) -> Result<(), Error> { - parse_time_span(i)?; - Ok(()) -} - #[cfg(test)] mod test { use anyhow::bail; + use crate::*; - use super::*; fn test_event(v: &'static str) -> Result<(), Error> { match parse_calendar_event(v) { diff --git a/proxmox-time/src/time_span.rs b/proxmox-time/src/time_span.rs new file mode 100644 index 0000000..2f8cf59 --- /dev/null +++ b/proxmox-time/src/time_span.rs @@ -0,0 +1,265 @@ +use std::collections::HashMap; + +use anyhow::Error; +use lazy_static::lazy_static; +use nom::{bytes::complete::take_while1, character::complete::space0, combinator::opt}; + +use crate::parse_helpers::{parse_complete_line, parse_error, parse_u64, IResult}; + +lazy_static! { + static ref TIME_SPAN_UNITS: HashMap<&'static str, f64> = { + let mut map = HashMap::new(); + + let second = 1.0; + + map.insert("seconds", second); + map.insert("second", second); + map.insert("sec", second); + map.insert("s", second); + + let msec = second / 1000.0; + + map.insert("msec", msec); + map.insert("ms", msec); + + let usec = msec / 1000.0; + + map.insert("usec", usec); + map.insert("us", usec); + map.insert("µs", usec); + + let nsec = usec / 1000.0; + + map.insert("nsec", nsec); + map.insert("ns", nsec); + + let minute = second * 60.0; + + map.insert("minutes", minute); + map.insert("minute", minute); + map.insert("min", minute); + map.insert("m", minute); + + let hour = minute * 60.0; + + map.insert("hours", hour); + map.insert("hour", hour); + map.insert("hr", hour); + map.insert("h", hour); + + let day = hour * 24.0; + + map.insert("days", day); + map.insert("day", day); + map.insert("d", day); + + let week = day * 7.0; + + map.insert("weeks", week); + map.insert("week", week); + map.insert("w", week); + + let month = 30.44 * day; + + map.insert("months", month); + map.insert("month", month); + map.insert("M", month); + + let year = 365.25 * day; + + map.insert("years", year); + map.insert("year", year); + map.insert("y", year); + + map + }; +} + +/// A time spans defines a time duration +#[derive(Default, Clone, Debug)] +pub struct TimeSpan { + pub nsec: u64, + pub usec: u64, + pub msec: u64, + pub seconds: u64, + pub minutes: u64, + pub hours: u64, + pub days: u64, + pub weeks: u64, + pub months: u64, + pub years: u64, +} + +impl From for f64 { + fn from(ts: TimeSpan) -> Self { + (ts.seconds as f64) + + ((ts.nsec as f64) / 1_000_000_000.0) + + ((ts.usec as f64) / 1_000_000.0) + + ((ts.msec as f64) / 1_000.0) + + ((ts.minutes as f64) * 60.0) + + ((ts.hours as f64) * 3600.0) + + ((ts.days as f64) * 3600.0 * 24.0) + + ((ts.weeks as f64) * 3600.0 * 24.0 * 7.0) + + ((ts.months as f64) * 3600.0 * 24.0 * 30.44) + + ((ts.years as f64) * 3600.0 * 24.0 * 365.25) + } +} + +impl From for TimeSpan { + fn from(duration: std::time::Duration) -> Self { + let mut duration = duration.as_nanos(); + let nsec = (duration % 1000) as u64; + duration /= 1000; + let usec = (duration % 1000) as u64; + duration /= 1000; + let msec = (duration % 1000) as u64; + duration /= 1000; + let seconds = (duration % 60) as u64; + duration /= 60; + let minutes = (duration % 60) as u64; + duration /= 60; + let hours = (duration % 24) as u64; + duration /= 24; + let years = (duration as f64 / 365.25) as u64; + let ydays = (duration as f64 % 365.25) as u64; + let months = (ydays as f64 / 30.44) as u64; + let mdays = (ydays as f64 % 30.44) as u64; + let weeks = mdays / 7; + let days = mdays % 7; + Self { + nsec, + usec, + msec, + seconds, + minutes, + hours, + days, + weeks, + months, + years, + } + } +} + +impl std::fmt::Display for TimeSpan { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + let mut first = true; + { + // block scope for mutable borrows + let mut do_write = |v: u64, unit: &str| -> Result<(), std::fmt::Error> { + if !first { + write!(f, " ")?; + } + first = false; + write!(f, "{}{}", v, unit) + }; + if self.years > 0 { + do_write(self.years, "y")?; + } + if self.months > 0 { + do_write(self.months, "m")?; + } + if self.weeks > 0 { + do_write(self.weeks, "w")?; + } + if self.days > 0 { + do_write(self.days, "d")?; + } + if self.hours > 0 { + do_write(self.hours, "h")?; + } + if self.minutes > 0 { + do_write(self.minutes, "min")?; + } + } + if !first { + write!(f, " ")?; + } + let seconds = self.seconds as f64 + (self.msec as f64 / 1000.0); + if seconds >= 0.1 { + if seconds >= 1.0 || !first { + write!(f, "{:.0}s", seconds)?; + } else { + write!(f, "{:.1}s", seconds)?; + } + } else if first { + write!(f, "<0.1s")?; + } + Ok(()) + } +} + +fn parse_time_unit(i: &str) -> IResult<&str, &str> { + let (n, text) = take_while1(|c: char| char::is_ascii_alphabetic(&c) || c == 'µ')(i)?; + if TIME_SPAN_UNITS.contains_key(&text) { + Ok((n, text)) + } else { + Err(parse_error(text, "time unit")) + } +} + +/// Parse a [TimeSpan] +pub fn parse_time_span(i: &str) -> Result { + parse_complete_line("time span", i, parse_time_span_incomplete) +} + +fn parse_time_span_incomplete(mut i: &str) -> IResult<&str, TimeSpan> { + let mut ts = TimeSpan::default(); + + loop { + i = space0(i)?.0; + if i.is_empty() { + break; + } + let (n, num) = parse_u64(i)?; + i = space0(n)?.0; + + if let (n, Some(unit)) = opt(parse_time_unit)(i)? { + i = n; + match unit { + "seconds" | "second" | "sec" | "s" => { + ts.seconds += num; + } + "msec" | "ms" => { + ts.msec += num; + } + "usec" | "us" | "µs" => { + ts.usec += num; + } + "nsec" | "ns" => { + ts.nsec += num; + } + "minutes" | "minute" | "min" | "m" => { + ts.minutes += num; + } + "hours" | "hour" | "hr" | "h" => { + ts.hours += num; + } + "days" | "day" | "d" => { + ts.days += num; + } + "weeks" | "week" | "w" => { + ts.weeks += num; + } + "months" | "month" | "M" => { + ts.months += num; + } + "years" | "year" | "y" => { + ts.years += num; + } + _ => return Err(parse_error(unit, "internal error")), + } + } else { + ts.seconds += num; + } + } + + Ok((i, ts)) +} + +/// Verify the format of the [TimeSpan] +pub fn verify_time_span(i: &str) -> Result<(), Error> { + parse_time_span(i)?; + Ok(()) +} + -- 2.30.2