From cfce8e70d177e3a72fe73dab6c99748fdb3ae7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Eustace?= Date: Sat, 5 Aug 2023 00:13:17 +0200 Subject: [PATCH] Lint Rust code --- .pre-commit-config.yaml | 9 ++ Makefile | 68 ++++++++++ rust/constants.rs | 27 +--- rust/helpers.rs | 16 +-- rust/parsing.rs | 210 ++++++++++++++---------------- rust/python/helpers.rs | 86 ++++++------ rust/python/parsing.rs | 62 ++++----- rust/python/types/duration.rs | 1 + rust/python/types/precise_diff.rs | 1 + rust/python/types/timezone.rs | 4 +- 10 files changed, 268 insertions(+), 216 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2974fac7..ff460a86 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,3 +20,12 @@ repos: rev: v0.0.270 hooks: - id: ruff + + - repo: local + hooks: + - id: lint-rust + name: Lint Rust + entry: make lint-rust + types: [rust] + language: rust + pass_filenames: false diff --git a/Makefile b/Makefile index e68b94c1..b15183a1 100644 --- a/Makefile +++ b/Makefile @@ -51,3 +51,71 @@ build_wheels_i686: # run tests against all supported python versions tox: @tox + + +lint-rust: + cargo fmt --version + cargo fmt --all -- --check + cargo clippy --version + cargo clippy --tests -- \ + -D warnings \ + -W clippy::pedantic \ + -W clippy::dbg_macro \ + -W clippy::print_stdout \ + -A clippy::cast-possible-truncation \ + -A clippy::cast-possible-wrap \ + -A clippy::cast-precision-loss \ + -A clippy::cast-sign-loss \ + -A clippy::doc-markdown \ + -A clippy::float-cmp \ + -A clippy::fn-params-excessive-bools \ + -A clippy::if-not-else \ + -A clippy::manual-let-else \ + -A clippy::match-bool \ + -A clippy::match-same-arms \ + -A clippy::missing-errors-doc \ + -A clippy::missing-panics-doc \ + -A clippy::module-name-repetitions \ + -A clippy::must-use-candidate \ + -A clippy::needless-pass-by-value \ + -A clippy::similar-names \ + -A clippy::single-match-else \ + -A clippy::struct-excessive-bools \ + -A clippy::too-many-lines \ + -A clippy::unnecessary-wraps \ + -A clippy::unused-self \ + -A clippy::used-underscore-binding + + +format-rust: + cargo fmt --version + cargo fmt --all + cargo clippy --version + cargo clippy --tests --fix --allow-dirty -- \ + -D warnings \ + -W clippy::pedantic \ + -W clippy::dbg_macro \ + -W clippy::print_stdout \ + -A clippy::cast-possible-truncation \ + -A clippy::cast-possible-wrap \ + -A clippy::cast-precision-loss \ + -A clippy::cast-sign-loss \ + -A clippy::doc-markdown \ + -A clippy::float-cmp \ + -A clippy::fn-params-excessive-bools \ + -A clippy::if-not-else \ + -A clippy::manual-let-else \ + -A clippy::match-bool \ + -A clippy::match-same-arms \ + -A clippy::missing-errors-doc \ + -A clippy::missing-panics-doc \ + -A clippy::module-name-repetitions \ + -A clippy::must-use-candidate \ + -A clippy::needless-pass-by-value \ + -A clippy::similar-names \ + -A clippy::single-match-else \ + -A clippy::struct-excessive-bools \ + -A clippy::too-many-lines \ + -A clippy::unnecessary-wraps \ + -A clippy::unused-self \ + -A clippy::used-underscore-binding diff --git a/rust/constants.rs b/rust/constants.rs index e48420b5..3fea9c02 100644 --- a/rust/constants.rs +++ b/rust/constants.rs @@ -3,14 +3,12 @@ pub const EPOCH_YEAR: u32 = 1970; pub const DAYS_PER_N_YEAR: u32 = 365; pub const DAYS_PER_L_YEAR: u32 = 366; -pub const USECS_PER_SEC: u32 = 1000000; - pub const SECS_PER_MIN: u32 = 60; pub const SECS_PER_HOUR: u32 = SECS_PER_MIN * 60; pub const SECS_PER_DAY: u32 = SECS_PER_HOUR * 24; // 400-year chunks always have 146097 days (20871 weeks). -pub const DAYS_PER_400_YEARS: u32 = 146097; +pub const DAYS_PER_400_YEARS: u32 = 146_097; pub const SECS_PER_400_YEARS: u64 = DAYS_PER_400_YEARS as u64 * SECS_PER_DAY as u64; // The number of seconds in an aligned 100-year chunk, for those that @@ -22,9 +20,10 @@ pub const SECS_PER_100_YEARS: [u64; 2] = [ // The number of seconds in an aligned 4-year chunk, for those that // do not begin with a leap year and those that do respectively. +#[allow(clippy::erasing_op)] pub const SECS_PER_4_YEARS: [u32; 2] = [ (4 * DAYS_PER_N_YEAR + 0 * DAYS_PER_L_YEAR) * SECS_PER_DAY, - (3 * DAYS_PER_N_YEAR + 1 * DAYS_PER_L_YEAR) * SECS_PER_DAY, + (3 * DAYS_PER_N_YEAR + DAYS_PER_L_YEAR) * SECS_PER_DAY, ]; // The number of seconds in non-leap and leap years respectively. @@ -33,8 +32,6 @@ pub const SECS_PER_YEAR: [u32; 2] = [ DAYS_PER_L_YEAR * SECS_PER_DAY, ]; -pub const MONTHS_PER_YEAR: u32 = 12; - // The month lengths in non-leap and leap years respectively. pub const DAYS_PER_MONTHS: [[i32; 13]; 2] = [ [-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], @@ -55,23 +52,5 @@ pub const MONTHS_OFFSETS: [[i32; 14]; 2] = [ pub const DAY_OF_WEEK_TABLE: [u32; 12] = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]; -pub const TM_SUNDAY: usize = 0; -pub const TM_MONDAY: usize = 1; -pub const TM_TUESDAY: usize = 2; -pub const TM_WEDNESDAY: usize = 3; -pub const TM_THURSDAY: usize = 4; -pub const TM_FRIDAY: usize = 5; -pub const TM_SATURDAY: usize = 6; - pub const TM_JANUARY: usize = 0; -pub const TM_FEBRUARY: usize = 1; -pub const TM_MARCH: usize = 2; -pub const TM_APRIL: usize = 3; -pub const TM_MAY: usize = 4; -pub const TM_JUNE: usize = 5; -pub const TM_JULY: usize = 6; -pub const TM_AUGUST: usize = 7; -pub const TM_SEPTEMBER: usize = 8; -pub const TM_OCTOBER: usize = 9; -pub const TM_NOVEMBER: usize = 10; pub const TM_DECEMBER: usize = 11; diff --git a/rust/helpers.rs b/rust/helpers.rs index 5edbeb57..364075ac 100644 --- a/rust/helpers.rs +++ b/rust/helpers.rs @@ -5,7 +5,7 @@ use crate::constants::{ }; fn p(year: i32) -> i32 { - return year + year / 4 - year / 100 + year / 400; + year + year / 4 - year / 100 + year / 400 } pub fn is_leap(year: i32) -> bool { @@ -25,7 +25,7 @@ pub fn days_in_year(year: i32) -> u32 { } pub fn week_day(year: i32, month: u32, day: u32) -> u32 { - let y: i32 = year - (month < 3) as i32; + let y: i32 = year - i32::from(month < 3); let w: i32 = (p(y) + DAY_OF_WEEK_TABLE[(month - 1) as usize] as i32 + day as i32) % 7; @@ -33,14 +33,14 @@ pub fn week_day(year: i32, month: u32, day: u32) -> u32 { return 7; } - w.abs() as u32 + w.unsigned_abs() } pub fn day_number(year: i32, month: u8, day: u8) -> i32 { - let m = ((month + 9) % 12) as i32; + let m = i32::from((month + 9) % 12); let y = year - m / 10; - return 365 * y + y / 4 - y / 100 + y / 400 + (m * 306 + 5) / 10 + (day as i32 - 1); + 365 * y + y / 4 - y / 100 + y / 400 + (m * 306 + 5) / 10 + (i32::from(day) - 1) } pub fn local_time( @@ -56,7 +56,7 @@ pub fn local_time( seconds -= (10957 * SECS_PER_DAY as usize) as isize; year += 30; // == 2000 } else { - seconds += ((146097 - 10957) * SECS_PER_DAY as usize) as isize; + seconds += ((146_097 - 10957) * SECS_PER_DAY as usize) as isize; year -= 370; // == 1600 } @@ -97,12 +97,12 @@ pub fn local_time( } // Handle months and days - let mut month = (TM_DECEMBER + 1) as usize; + let mut month = TM_DECEMBER + 1; let mut day: usize = (seconds / (SECS_PER_DAY as isize) + 1) as usize; seconds %= SECS_PER_DAY as isize; let mut month_offset: usize; - while month != (TM_JANUARY + 1) as usize { + while month != (TM_JANUARY + 1) { month_offset = MONTHS_OFFSETS[leap_year][month] as usize; if day > month_offset { day -= month_offset; diff --git a/rust/parsing.rs b/rust/parsing.rs index ce5803ee..c17ed714 100644 --- a/rust/parsing.rs +++ b/rust/parsing.rs @@ -2,24 +2,19 @@ use core::str; use std::{fmt, str::CharIndices}; use crate::{ - constants::{DAYS_PER_MONTHS, MONTHS_OFFSETS}, + constants::MONTHS_OFFSETS, helpers::{days_in_year, is_leap, is_long_year, week_day}, }; -pub struct Duration { - years: i32, -} - #[derive(Debug, Clone)] pub struct ParseError { index: usize, - c: char, message: String, } impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{} (Position: {})", self.message, self.index.to_string()) + write!(f, "{} (Position: {})", self.message, self.index) } } @@ -40,7 +35,7 @@ pub struct ParsedDateTime { pub time_is_midnight: bool, } -impl<'a> ParsedDateTime { +impl ParsedDateTime { pub fn new() -> ParsedDateTime { ParsedDateTime { year: 0, @@ -72,7 +67,7 @@ pub struct ParsedDuration { pub microseconds: u32, } -impl<'a> ParsedDuration { +impl ParsedDuration { pub fn new() -> ParsedDuration { ParsedDuration { years: 0, @@ -93,7 +88,7 @@ pub struct Parsed { pub second_datetime: Option, } -impl<'a> Parsed { +impl Parsed { pub fn new() -> Parsed { Parsed { datetime: None, @@ -147,8 +142,7 @@ impl<'a> Parser<'a> { fn parse_error(&mut self, message: String) -> ParseError { ParseError { index: self.idx, - c: self.current, - message: message, + message, } } @@ -195,7 +189,7 @@ impl<'a> Parser<'a> { } if self.current >= '0' && self.current <= '9' { - value = 10 * value + self.current.to_digit(10).unwrap() as u32; + value = 10 * value + self.current.to_digit(10).unwrap(); self.inc(); } else { return Err(self.unexpected_character_error(field_name, length - i)); @@ -225,7 +219,7 @@ impl<'a> Parser<'a> { self.parse_time(&mut datetime, false)?; if !self.end() { - return Err(self.parse_error(format!("Unconverted data remains"))); + return Err(self.parse_error("Unconverted data remains".to_string())); } match &parsed.datetime { @@ -255,7 +249,7 @@ impl<'a> Parser<'a> { self.parse_time(&mut datetime, true)?; if !self.end() { - return Err(self.parse_error(format!("Unconverted data remains"))); + return Err(self.parse_error("Unconverted data remains".to_string())); } match &parsed.datetime { @@ -341,19 +335,38 @@ impl<'a> Parser<'a> { datetime.day = 1; } } - } else { - if self.current == 'W' { - // Compact ISO week and day (WwwD) - self.inc(); + } else if self.current == 'W' { + // Compact ISO week and day (WwwD) + self.inc(); - let iso_week = self.parse_integer(2, "iso week")?; - let mut iso_day: u32 = 1; + let iso_week = self.parse_integer(2, "iso week")?; + let mut iso_day: u32 = 1; - if !self.end() && self.current != ' ' && self.current != 'T' { - iso_day = self.parse_integer(1, "iso day")?; - } + if !self.end() && self.current != ' ' && self.current != 'T' { + iso_day = self.parse_integer(1, "iso day")?; + } - match self.iso_to_ymd(datetime.year, iso_week, iso_day) { + match self.iso_to_ymd(datetime.year, iso_week, iso_day) { + Ok((year, month, day)) => { + datetime.year = year; + datetime.month = month; + datetime.day = day; + } + Err(error) => return Err(error), + } + } else { + /* + Month and day in compact format (MMDD) or ordinal date (DDD) + We'll assume first that the next part is a month and adjust if not. + */ + datetime.month = self.parse_integer(2, "month")?; + let mut ordinal_day = self.parse_integer(1, "ordinal day")? as i32; + + if self.end() || self.current == ' ' || self.current == 'T' { + // Ordinal day + ordinal_day += datetime.month as i32 * 10; + + match self.ordinal_to_ymd(datetime.year, ordinal_day, false) { Ok((year, month, day)) => { datetime.year = year; datetime.month = month; @@ -362,29 +375,8 @@ impl<'a> Parser<'a> { Err(error) => return Err(error), } } else { - /* - Month and day in compact format (MMDD) or ordinal date (DDD) - We'll assume first that the next part is a month and adjust if not. - */ - datetime.month = self.parse_integer(2, "month")?; - let mut ordinal_day = self.parse_integer(1, "ordinal day")? as i32; - - if self.end() || self.current == ' ' || self.current == 'T' { - // Ordinal day - ordinal_day = datetime.month as i32 * 10 + ordinal_day; - - match self.ordinal_to_ymd(datetime.year, ordinal_day, false) { - Ok((year, month, day)) => { - datetime.year = year; - datetime.month = month; - datetime.day = day; - } - Err(error) => return Err(error), - } - } else { - // Day - datetime.day = ordinal_day as u32 * 10 + self.parse_integer(1, "day")?; - } + // Day + datetime.day = ordinal_day as u32 * 10 + self.parse_integer(1, "day")?; } } @@ -409,7 +401,7 @@ impl<'a> Parser<'a> { return Ok(()); } - return Err(self.parse_error(format!("Unconverted data remains"))); + return Err(self.parse_error("Unconverted data remains".to_string())); } match &parsed.datetime { @@ -512,7 +504,7 @@ impl<'a> Parser<'a> { } if !datetime.extended_date_format { - return Err(self.parse_error(format!("Cannot combine \"basic\" date format with \"extended\" time format (Should be either `YYYY-MM-DDThh:mm:ss` or `YYYYMMDDThhmmss`)."))); + return Err(self.parse_error("Cannot combine \"basic\" date format with \"extended\" time format (Should be either `YYYY-MM-DDThh:mm:ss` or `YYYYMMDDThhmmss`).".to_string())); } } } else { @@ -563,7 +555,7 @@ impl<'a> Parser<'a> { } if datetime.extended_date_format { - return Err(self.parse_error(format!("Cannot combine \"extended\" date format with \"basic\" time format (Should be either `YYYY-MM-DDThh:mm:ss` or `YYYYMMDDThhmmss`)."))); + return Err(self.parse_error("Cannot combine \"extended\" date format with \"basic\" time format (Should be either `YYYY-MM-DDThh:mm:ss` or `YYYYMMDDThhmmss`).".to_string())); } } } @@ -576,7 +568,7 @@ impl<'a> Parser<'a> { // Special case for 24:00:00, which is valid for ISO 8601. // This is equivalent to 00:00:00 the next day. // We will store the information for now. - datetime.time_is_midnight = true + datetime.time_is_midnight = true; } if self.current == 'Z' || self.current == '+' || self.current == '-' { @@ -606,24 +598,24 @@ impl<'a> Parser<'a> { tzminute = self.parse_integer(2, "timezone minute")? as i32; } } else { - datetime.tzname = Some("UTC".to_string()) + datetime.tzname = Some("UTC".to_string()); } if tzminute > 59 { - return Err(self.parse_error(format!("timezone minute must be in 0..59"))); + return Err(self.parse_error("timezone minute must be in 0..59".to_string())); } tzminute += tzhour * 60; tzminute *= tzsign; if tzminute.abs() > 1440 { - return Err(self.parse_error(format!("The absolute offset is to large"))); + return Err(self.parse_error("The absolute offset is to large".to_string())); } datetime.offset = Some(tzminute * 60); } - return Ok(()); + Ok(()) } fn parse_duration(&mut self, parsed: &mut Parsed) -> Result<(), ParseError> { @@ -639,7 +631,7 @@ impl<'a> Parser<'a> { 'T' => { if got_t { return Err( - self.parse_error(format!("Repeated time declaration in duration")) + self.parse_error("Repeated time declaration in duration".to_string()) ); } @@ -648,7 +640,7 @@ impl<'a> Parser<'a> { _c => { let (value, op_fraction) = self.parse_duration_number_frac()?; if last_had_fraction { - return Err(self.parse_error(format!("Invalid duration fraction"))); + return Err(self.parse_error("Invalid duration fraction".to_string())); } if op_fraction.is_some() { @@ -663,45 +655,45 @@ impl<'a> Parser<'a> { || duration.microseconds != 0 { return Err( - self.parse_error(format!("Duration units out of order")) + self.parse_error("Duration units out of order".to_string()) ); } duration.hours += value; if let Some(fraction) = op_fraction { - let extra_minutes = fraction * 60 as f64; + let extra_minutes = fraction * 60_f64; let extra_full_minutes: f64 = extra_minutes.trunc(); duration.minutes += extra_full_minutes as u32; let extra_seconds = ((extra_minutes - extra_full_minutes) * 60.0).round(); let extra_full_seconds = extra_seconds.trunc(); - duration.seconds = duration.seconds + extra_full_seconds as u32; + duration.seconds += extra_full_seconds as u32; let micro_extra = ((extra_seconds - extra_full_seconds) * 1_000_000.0) .round() as u32; - duration.microseconds = duration.microseconds + micro_extra; + duration.microseconds += micro_extra; } } 'M' => { if duration.seconds != 0 || duration.microseconds != 0 { return Err( - self.parse_error(format!("Duration units out of order")) + self.parse_error("Duration units out of order".to_string()) ); } duration.minutes += value; if let Some(fraction) = op_fraction { - let extra_seconds = fraction * 60 as f64; + let extra_seconds = fraction * 60_f64; let extra_full_seconds = extra_seconds.trunc(); - duration.seconds = duration.seconds + extra_full_seconds as u32; + duration.seconds += extra_full_seconds as u32; let micro_extra = ((extra_seconds - extra_full_seconds) * 1_000_000.0) .round() as u32; - duration.microseconds = duration.microseconds + micro_extra; + duration.microseconds += micro_extra; } } 'S' => { @@ -713,21 +705,24 @@ impl<'a> Parser<'a> { } } _ => { - return Err(self.parse_error(format!("Invalid duration time unit"))) + return Err( + self.parse_error("Invalid duration time unit".to_string()) + ) } } } else { match self.current { 'Y' => { if last_had_fraction { - return Err(self.parse_error(format!( + return Err(self.parse_error( "Fractional years in duration are not supported" - ))); + .to_string(), + )); } if duration.months != 0 || duration.days != 0 { return Err( - self.parse_error(format!("Duration units out of order")) + self.parse_error("Duration units out of order".to_string()) ); } @@ -735,14 +730,15 @@ impl<'a> Parser<'a> { } 'M' => { if last_had_fraction { - return Err(self.parse_error(format!( + return Err(self.parse_error( "Fractional months in duration are not supported" - ))); + .to_string(), + )); } if duration.days != 0 { return Err( - self.parse_error(format!("Duration units out of order")) + self.parse_error("Duration units out of order".to_string()) ); } @@ -750,17 +746,17 @@ impl<'a> Parser<'a> { } 'W' => { if duration.years != 0 || duration.months != 0 { - return Err(self.parse_error(format!( - "Basic format durations cannot have weeks" - ))); + return Err(self.parse_error( + "Basic format durations cannot have weeks".to_string(), + )); } duration.weeks = value; if let Some(fraction) = op_fraction { - let extra_days = fraction * 7 as f64; + let extra_days = fraction * 7_f64; let extra_full_days = extra_days.trunc(); - duration.days = duration.days + extra_full_days as u32; + duration.days += extra_full_days as u32; let extra_hours = (extra_days - extra_full_days) * 24.0; let extra_full_hours = extra_hours.trunc(); duration.hours += extra_full_hours as u32; @@ -771,19 +767,19 @@ impl<'a> Parser<'a> { let extra_seconds = ((extra_minutes - extra_full_minutes) * 60.0).round(); let extra_full_seconds = extra_seconds.trunc(); - duration.seconds = duration.seconds + extra_full_seconds as u32; + duration.seconds += extra_full_seconds as u32; let micro_extra = ((extra_seconds - extra_full_seconds) * 1_000_000.0) .round() as u32; - duration.microseconds = duration.microseconds + micro_extra; + duration.microseconds += micro_extra; } } 'D' => { if duration.weeks != 0 { - return Err(self.parse_error(format!( - "Week format durations cannot have days" - ))); + return Err(self.parse_error( + "Week format durations cannot have days".to_string(), + )); } duration.days += value; @@ -798,21 +794,22 @@ impl<'a> Parser<'a> { let extra_seconds = ((extra_minutes - extra_full_minutes) * 60.0).round(); let extra_full_seconds = extra_seconds.trunc(); - duration.seconds = duration.seconds + extra_full_seconds as u32; + duration.seconds += extra_full_seconds as u32; let micro_extra = ((extra_seconds - extra_full_seconds) * 1_000_000.0) .round() as u32; - duration.microseconds = duration.microseconds + micro_extra; + duration.microseconds += micro_extra; } } _ => { - return Err(self.parse_error(format!("Invalid duration time unit"))) + return Err( + self.parse_error("Invalid duration time unit".to_string()) + ) } } } } - _ => break, } self.inc(); @@ -823,7 +820,7 @@ impl<'a> Parser<'a> { parsed.duration = Some(duration); - return Ok(()); + Ok(()) } fn parse_duration_number_frac(&mut self) -> Result<(u32, Option), ParseError> { @@ -837,7 +834,7 @@ impl<'a> Parser<'a> { match self.current { c if c.is_ascii_digit() => { decimal *= 10.0; - decimal += c.to_digit(10).unwrap() as f64; + decimal += f64::from(c.to_digit(10).unwrap()); denominator *= 10.0; } _ => return Ok((value, Some(decimal / denominator))), @@ -850,9 +847,9 @@ impl<'a> Parser<'a> { fn parse_duration_number(&mut self) -> Result { let mut value = match self.current { - c if c.is_ascii_digit() => c.to_digit(10).unwrap() as u32, + c if c.is_ascii_digit() => c.to_digit(10).unwrap(), _ => { - return Err(self.parse_error(format!("Invalid number in duration"))); + return Err(self.parse_error("Invalid number in duration".to_string())); } }; @@ -861,8 +858,8 @@ impl<'a> Parser<'a> { match self.current { c if c.is_ascii_digit() => { - value = value * 10; - value = value + c.to_digit(10).unwrap() as u32; + value *= 10; + value += c.to_digit(10).unwrap(); } _ => return Ok(value), } @@ -878,10 +875,8 @@ impl<'a> Parser<'a> { if iso_week > 53 || iso_week > 52 && !is_long_year(iso_year as i32) { return Err(ParseError { index: self.idx, - c: self.current, message: format!( - "Invalid ISO date: week {} out of range for year {}", - iso_week, iso_year + "Invalid ISO date: week {iso_week} out of range for year {iso_year}" ), }); } @@ -889,8 +884,7 @@ impl<'a> Parser<'a> { if iso_day > 7 { return Err(ParseError { index: self.idx, - c: self.current, - message: format!("Invalid ISO date: week day is invalid"), + message: "Invalid ISO date: week day is invalid".to_string(), }); } @@ -908,35 +902,31 @@ impl<'a> Parser<'a> { ) -> Result<(u32, u32, u32), ParseError> { let mut ord: i32 = ordinal; let mut y: u32 = year; - let mut leap: usize = is_leap(y as i32) as usize; + let mut leap: usize = usize::from(is_leap(y as i32)); if ord < 1 { if !allow_out_of_bounds { return Err(self.parse_error(format!( - "Invalid ordinal day: {} is too small for year {}", - ordinal.to_string(), - year.to_string() + "Invalid ordinal day: {ordinal} is too small for year {year}" ))); } // Previous year ord += days_in_year((year - 1) as i32) as i32; y -= 1; - leap = is_leap(y as i32) as usize; + leap = usize::from(is_leap(y as i32)); } if ord > days_in_year(y as i32) as i32 { if !allow_out_of_bounds { return Err(self.parse_error(format!( - "Invalid ordinal day: {} is too large for year {}", - ordinal.to_string(), - year.to_string() + "Invalid ordinal day: {ordinal} is too large for year {year}" ))); } // Next year ord -= days_in_year(y as i32) as i32; y += 1; - leap = is_leap(y as i32) as usize; + leap = usize::from(is_leap(y as i32)); } for i in 1..14 { @@ -944,14 +934,12 @@ impl<'a> Parser<'a> { let day = ord as u32 - MONTHS_OFFSETS[leap][i - 1] as u32; let month = (i - 1) as u32; - return Ok((y as u32, month, day)); + return Ok((y, month, day)); } } Err(self.parse_error(format!( - "Invalid ordinal day: {} is too large for year {}", - ordinal.to_string(), - year.to_string() + "Invalid ordinal day: {ordinal} is too large for year {year}" ))) } } diff --git a/rust/python/helpers.rs b/rust/python/helpers.rs index 6ac33be5..4a53e595 100644 --- a/rust/python/helpers.rs +++ b/rust/python/helpers.rs @@ -1,3 +1,5 @@ +use std::cmp::Ordering; + use pyo3::{ intern, prelude::*, @@ -28,7 +30,7 @@ struct DateTimeInfo<'py> { impl PartialEq for DateTimeInfo<'_> { fn eq(&self, other: &Self) -> bool { - return ( + ( self.year, self.month, self.day, @@ -45,13 +47,13 @@ impl PartialEq for DateTimeInfo<'_> { other.minute, other.second, other.microsecond, - )); + )) } } impl PartialOrd for DateTimeInfo<'_> { fn partial_cmp(&self, other: &Self) -> Option { - return ( + ( self.year, self.month, self.day, @@ -68,7 +70,7 @@ impl PartialOrd for DateTimeInfo<'_> { other.minute, other.second, other.microsecond, - )); + )) } } @@ -82,7 +84,7 @@ pub fn get_tz_name<'py>(py: Python, dt: &'py PyAny) -> PyResult<&'py str> { let tzinfo = dt.getattr("tzinfo"); match tzinfo { - Err(_) => return Ok(tz), + Err(_) => Ok(tz), Ok(tzinfo) => { if tzinfo.is_none() { return Ok(tz); @@ -114,14 +116,14 @@ pub fn get_tz_name<'py>(py: Python, dt: &'py PyAny) -> PyResult<&'py str> { .unwrap(); return tzname.to_str(); - } else { - return Ok(tz); } + + Ok(tz) } } } -pub fn get_offset<'py>(dt: &'py PyAny) -> PyResult { +pub fn get_offset(dt: &PyAny) -> PyResult { if !PyDateTime::is_type_of(dt) { return Ok(0); } @@ -134,7 +136,7 @@ pub fn get_offset<'py>(dt: &'py PyAny) -> PyResult { let offset: &PyDelta = tzinfo.call_method1("utcoffset", (dt,))?.downcast()?; - return Ok(offset.get_days() * SECS_PER_DAY as i32 + offset.get_seconds()); + Ok(offset.get_days() * SECS_PER_DAY as i32 + offset.get_seconds()) } #[pyfunction] @@ -171,8 +173,8 @@ pub fn precise_diff<'py>(py: Python, dt1: &'py PyAny, dt2: &'py PyAny) -> PyResu let mut sign = 1; let mut dtinfo1 = DateTimeInfo { year: dt1.downcast::()?.get_year(), - month: dt1.downcast::()?.get_month() as i32, - day: dt1.downcast::()?.get_day() as i32, + month: i32::from(dt1.downcast::()?.get_month()), + day: i32::from(dt1.downcast::()?.get_day()), hour: 0, minute: 0, second: 0, @@ -184,8 +186,8 @@ pub fn precise_diff<'py>(py: Python, dt1: &'py PyAny, dt2: &'py PyAny) -> PyResu }; let mut dtinfo2 = DateTimeInfo { year: dt2.downcast::()?.get_year(), - month: dt2.downcast::()?.get_month() as i32, - day: dt2.downcast::()?.get_day() as i32, + month: i32::from(dt2.downcast::()?.get_month()), + day: i32::from(dt2.downcast::()?.get_day()), hour: 0, minute: 0, second: 0, @@ -195,16 +197,16 @@ pub fn precise_diff<'py>(py: Python, dt1: &'py PyAny, dt2: &'py PyAny) -> PyResu offset: get_offset(dt2)?, is_datetime: PyDateTime::is_type_of(dt2), }; - let in_same_tz: bool = dtinfo1.tz == dtinfo2.tz && dtinfo1.tz.len() > 0; + let in_same_tz: bool = dtinfo1.tz == dtinfo2.tz && !dtinfo1.tz.is_empty(); let mut total_days = helpers::day_number(dtinfo2.year, dtinfo2.month as u8, dtinfo2.day as u8) - helpers::day_number(dtinfo1.year, dtinfo1.month as u8, dtinfo1.day as u8); if dtinfo1.is_datetime { let dt1dt: &PyDateTime = dt1.downcast()?; - dtinfo1.hour = dt1dt.get_hour() as i32; - dtinfo1.minute = dt1dt.get_minute() as i32; - dtinfo1.second = dt1dt.get_second() as i32; + dtinfo1.hour = i32::from(dt1dt.get_hour()); + dtinfo1.minute = i32::from(dt1dt.get_minute()); + dtinfo1.second = i32::from(dt1dt.get_second()); dtinfo1.microsecond = dt1dt.get_microsecond() as i32; if !in_same_tz && dtinfo1.offset != 0 || total_days == 0 { @@ -247,9 +249,9 @@ pub fn precise_diff<'py>(py: Python, dt1: &'py PyAny, dt2: &'py PyAny) -> PyResu if dtinfo2.is_datetime { let dt2dt: &PyDateTime = dt2.downcast()?; - dtinfo2.hour = dt2dt.get_hour() as i32; - dtinfo2.minute = dt2dt.get_minute() as i32; - dtinfo2.second = dt2dt.get_second() as i32; + dtinfo2.hour = i32::from(dt2dt.get_hour()); + dtinfo2.minute = i32::from(dt2dt.get_minute()); + dtinfo2.second = i32::from(dt2dt.get_second()); dtinfo2.microsecond = dt2dt.get_microsecond() as i32; if !in_same_tz && dtinfo2.offset != 0 || total_days == 0 { @@ -305,7 +307,7 @@ pub fn precise_diff<'py>(py: Python, dt1: &'py PyAny, dt2: &'py PyAny) -> PyResu let mut microsecond_diff = dtinfo2.microsecond - dtinfo1.microsecond; if microsecond_diff < 0 { - microsecond_diff += 1000000; + microsecond_diff += 1_000_000; second_diff -= 1; } @@ -339,26 +341,30 @@ pub fn precise_diff<'py>(py: Python, dt1: &'py PyAny, dt2: &'py PyAny) -> PyResu let leap = helpers::is_leap(year); - let days_in_last_month = DAYS_PER_MONTHS[leap as usize][month as usize]; + let days_in_last_month = DAYS_PER_MONTHS[usize::from(leap)][month as usize]; let days_in_month = - DAYS_PER_MONTHS[helpers::is_leap(dtinfo2.year) as usize][dtinfo2.month as usize]; - - if day_diff < days_in_month - days_in_last_month { - // We don't have a full month, we calculate days - if (days_in_last_month < dtinfo1.day) { - day_diff += dtinfo1.day; - } else { + DAYS_PER_MONTHS[usize::from(helpers::is_leap(dtinfo2.year))][dtinfo2.month as usize]; + + match day_diff.cmp(&(days_in_month - days_in_last_month)) { + Ordering::Less => { + // We don't have a full month, we calculate days + if days_in_last_month < dtinfo1.day { + day_diff += dtinfo1.day; + } else { + day_diff += days_in_last_month; + } + } + Ordering::Equal => { + // We have exactly a full month + // We remove the days difference + // and add one to the months difference + day_diff = 0; + month_diff += 1; + } + Ordering::Greater => { + // We have a full month day_diff += days_in_last_month; } - } else if day_diff == days_in_month - days_in_last_month { - // We have exactly a full month - // We remove the days difference - // and add one to the months difference - day_diff = 0; - month_diff += 1; - } else { - // We have a full month - day_diff += days_in_last_month; } month_diff -= 1; @@ -369,7 +375,7 @@ pub fn precise_diff<'py>(py: Python, dt1: &'py PyAny, dt2: &'py PyAny) -> PyResu year_diff -= 1; } - return Ok(PreciseDiff { + Ok(PreciseDiff { years: year_diff * sign, months: month_diff * sign, days: day_diff * sign, @@ -378,5 +384,5 @@ pub fn precise_diff<'py>(py: Python, dt1: &'py PyAny, dt2: &'py PyAny) -> PyResu seconds: second_diff * sign, microseconds: microsecond_diff * sign, total_days: total_days * sign, - }); + }) } diff --git a/rust/python/parsing.rs b/rust/python/parsing.rs index 70fb1501..f12782ed 100644 --- a/rust/python/parsing.rs +++ b/rust/python/parsing.rs @@ -4,7 +4,7 @@ use pyo3::types::PyDate; use pyo3::types::PyDateTime; use pyo3::types::PyTime; -use crate::parsing::{ParseError, Parser}; +use crate::parsing::Parser; use crate::python::types::{Duration, FixedTimezone}; #[pyfunction] @@ -24,7 +24,7 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult { datetime.hour as u8, datetime.minute as u8, datetime.second as u8, - datetime.microsecond as u32, + datetime.microsecond, Some( Py::new(py, FixedTimezone::new(offset, datetime.tzname))? .to_object(py) @@ -32,7 +32,7 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult { ), )?; - return Ok(dt.to_object(py)); + Ok(dt.to_object(py)) } None => { let dt = PyDateTime::new( @@ -43,11 +43,11 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult { datetime.hour as u8, datetime.minute as u8, datetime.second as u8, - datetime.microsecond as u32, + datetime.microsecond, None, )?; - return Ok(dt.to_object(py)); + Ok(dt.to_object(py)) } }, (true, false) => { @@ -58,7 +58,7 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult { datetime.day as u8, )?; - return Ok(dt.to_object(py)); + Ok(dt.to_object(py)) } (false, true) => match datetime.offset { Some(offset) => { @@ -67,7 +67,7 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult { datetime.hour as u8, datetime.minute as u8, datetime.second as u8, - datetime.microsecond as u32, + datetime.microsecond, Some( Py::new(py, FixedTimezone::new(offset, datetime.tzname))? .to_object(py) @@ -75,7 +75,7 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult { ), )?; - return Ok(dt.to_object(py)); + Ok(dt.to_object(py)) } None => { let dt = PyTime::new( @@ -83,35 +83,35 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult { datetime.hour as u8, datetime.minute as u8, datetime.second as u8, - datetime.microsecond as u32, + datetime.microsecond, None, )?; - return Ok(dt.to_object(py)); + Ok(dt.to_object(py)) } }, - (_, _) => Err(exceptions::PyValueError::new_err(format!("Parsing error"))), + (_, _) => Err(exceptions::PyValueError::new_err( + "Parsing error".to_string(), + )), }, - (None, Some(duration), None) => { - return Ok(Py::new( - py, - Duration::new( - Some(duration.years), - Some(duration.months), - Some(duration.weeks), - Some(duration.days), - Some(duration.hours), - Some(duration.minutes), - Some(duration.seconds), - Some(duration.microseconds), - ), - )? - .to_object(py)); - } - (_, _, _) => Err(exceptions::PyValueError::new_err(format!( - "Not yet implemented" - ))), + (None, Some(duration), None) => Ok(Py::new( + py, + Duration::new( + Some(duration.years), + Some(duration.months), + Some(duration.weeks), + Some(duration.days), + Some(duration.hours), + Some(duration.minutes), + Some(duration.seconds), + Some(duration.microseconds), + ), + )? + .to_object(py)), + (_, _, _) => Err(exceptions::PyValueError::new_err( + "Not yet implemented".to_string(), + )), }, - Err(error) => Err(exceptions::PyValueError::new_err(format!("{}", error))), + Err(error) => Err(exceptions::PyValueError::new_err(format!("{error}"))), } } diff --git a/rust/python/types/duration.rs b/rust/python/types/duration.rs index fca4fe73..fc18f4eb 100644 --- a/rust/python/types/duration.rs +++ b/rust/python/types/duration.rs @@ -24,6 +24,7 @@ pub struct Duration { impl Duration { #[new] #[pyo3(signature = (years=0, months=0, weeks=0, days=0, hours=0, minutes=0, seconds=0, microseconds=0))] + #[allow(clippy::too_many_arguments)] pub fn new( years: Option, months: Option, diff --git a/rust/python/types/precise_diff.rs b/rust/python/types/precise_diff.rs index c9f67f9c..64ca3a65 100644 --- a/rust/python/types/precise_diff.rs +++ b/rust/python/types/precise_diff.rs @@ -24,6 +24,7 @@ pub struct PreciseDiff { impl PreciseDiff { #[new] #[pyo3(signature = (years=0, months=0, days=0, hours=0, minutes=0, seconds=0, microseconds=0, total_days=0))] + #[allow(clippy::too_many_arguments)] pub fn new( years: Option, months: Option, diff --git a/rust/python/types/timezone.rs b/rust/python/types/timezone.rs index c3a5565a..d7d801aa 100644 --- a/rust/python/types/timezone.rs +++ b/rust/python/types/timezone.rs @@ -1,5 +1,5 @@ use pyo3::prelude::*; -use pyo3::types::{PyDateTime, PyDelta, PyDict, PyTzInfo}; +use pyo3::types::{PyDelta, PyDict, PyTzInfo}; #[pyclass(module = "_pendulum", extends = PyTzInfo)] #[derive(Clone)] @@ -42,7 +42,7 @@ impl FixedTimezone { let sign = if self.offset < 0 { "-" } else { "+" }; let minutes = self.offset / 60; let (hour, minute) = (minutes.abs() / 60, minutes.abs() % 60); - format!("{}{:.2}:{:.2}", sign, hour, minute) + format!("{sign}{hour:.2}:{minute:.2}") } } }