From 41d07561e5451af9c033515fc7084be86d250326 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:24:40 +0200 Subject: [PATCH 01/15] Add whack support --- scripts/ci.sh | 17 +++++++++++++++++ scripts/clean_build.sh | 16 ++++++++++++++++ whack.toml | 5 +++++ 3 files changed, 38 insertions(+) create mode 100755 scripts/ci.sh create mode 100644 scripts/clean_build.sh create mode 100644 whack.toml diff --git a/scripts/ci.sh b/scripts/ci.sh new file mode 100755 index 0000000..bbc0c30 --- /dev/null +++ b/scripts/ci.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +start=$(date -Iseconds -u) +host_name=$(hostname) +echo "Starting build at: ${start} on ${host_name}" + +export CARGO_TARGET_DIR="${BUILD_OUTPUT}" +export RUST_BACKTRACE="full" +export PATH="/var/whack/.cargo/bin:$PATH" + +cargo deny --workspace -L info check +cargo check +cargo clippy +cargo doc --workspace --no-deps +cargo test diff --git a/scripts/clean_build.sh b/scripts/clean_build.sh new file mode 100644 index 0000000..0aad87f --- /dev/null +++ b/scripts/clean_build.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e + +start=$(date -Iseconds -u) +host_name=$(hostname) +echo "Starting build at: ${start} on ${host_name}" + +for dir in "${BUILD_OUTPUT}/debug/build" \ + "${BUILD_OUTPUT}/debug/deps" \ + "${BUILD_OUTPUT}/debug/incremental" +do + if [ -d "${dir}" ] ; then + find "${dir}" ! -newerct '15 days ago' -d -exec rm -rv {} \; + fi +done diff --git a/whack.toml b/whack.toml new file mode 100644 index 0000000..6919d4a --- /dev/null +++ b/whack.toml @@ -0,0 +1,5 @@ +worker_dependencies = ["rust"] + +[scripts] +run_tests = "scripts/ci.sh" +clean_build = "scripts/clean_build.sh" From a4c0211b879007344d4e97372af8551c6e7fb36e Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:25:05 +0200 Subject: [PATCH 02/15] Update `deny.toml` to latest version --- deny.toml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/deny.toml b/deny.toml index 0801a66..951f72b 100644 --- a/deny.toml +++ b/deny.toml @@ -1,9 +1,6 @@ [advisories] -vulnerability = "deny" -unmaintained = "deny" -notice = "deny" -unsound = "deny" -ignore = [] +version = 2 +yanked = "warn" [bans] multiple-versions = "allow" @@ -22,13 +19,10 @@ allow-registry = ["https://github.com/rust-lang/crates.io-index"] allow-git = [] [licenses] -unlicensed = "deny" -allow-osi-fsf-free = "neither" -copyleft = "deny" # We want really high confidence when inferring licenses from text confidence-threshold = 0.93 # (extending this list is only allowed after agreement by TD management) -allow = ["Apache-2.0", "Apache-2.0 WITH LLVM-exception", "MIT"] +allow = ["Apache-2.0", "MIT"] # ignore the local workspace crates [licenses.private] From 5ccf2da29c3a52111991cccf2ebd4a9b6d4b65dd Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:25:31 +0200 Subject: [PATCH 03/15] Update lints to opt out system --- .cargo/config.toml | 102 ---------------------------------------- Cargo.toml | 57 ++++++++++++++++++++++ cli/Cargo.toml | 3 ++ ocpi-tariffs/Cargo.toml | 3 ++ 4 files changed, 63 insertions(+), 102 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 3327840..fabd056 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -4,105 +4,3 @@ rustdocflags = [ "-Arustdoc::private_intra_doc_links", "-Drustdoc::broken_intra_doc_links", ] - -[target.'cfg(all())'] -rustflags = [ - # https://doc.rust-lang.org/rustc/lints/index.html - "-Wfuture_incompatible", - "-Wlet_underscore", - "-Wnonstandard-style", - "-Wrust_2018_compatibility", - "-Wrust_2018_idioms", - "-Wrust_2021_compatibility", - "-Wtrivial_casts", - "-Wtrivial_numeric_casts", - "-Wunsafe_code", - "-Wunused", - "-Wunused_import_braces", - "-Wunused_lifetimes", - "-Wunused_macro_rules", - "-Wunused_qualifications", - "-Wunused_tuple_struct_fields", - "-Wwarnings", - - # This list is based off Embarks clippy list - # https://github.com/EmbarkStudios/rust-ecosystem/blob/main/lints.rs - # - # You can lookup the motivation for each clippy here: - # https://rust-lang.github.io/rust-clippy/master/index.html - # - # The following lints are pending implementation, as they cause significant code churn - # - # "-Wclippy::string_lit_as_bytes", - # - # We also excluded the lint `clippy::map_unwrap_or` as it considers the pattern `map_or_else(.., ..)` more readable than `map(...).unwrap_or(..)` - # We do not. - - "-Aclippy::doc_markdown", - "-Wclippy::await_holding_lock", - "-Wclippy::char_lit_as_u8", - "-Wclippy::checked_conversions", - "-Wclippy::dbg_macro", - "-Wclippy::debug_assert_with_mut_call", - "-Wclippy::disallowed_macros", - "-Wclippy::disallowed_methods", - "-Wclippy::disallowed_types", - "-Wclippy::empty_enum", - "-Wclippy::enum_glob_use", - "-Wclippy::exit", - "-Wclippy::explicit_deref_methods", - "-Wclippy::explicit_into_iter_loop", - "-Wclippy::expl_impl_clone_on_copy", - "-Wclippy::fallible_impl_from", - "-Wclippy::filter_map_next", - "-Wclippy::flat_map_option", - "-Wclippy::float_cmp_const", - "-Wclippy::fn_params_excessive_bools", - "-Wclippy::from_iter_instead_of_collect", - "-Wclippy::if_let_mutex", - "-Wclippy::implicit_clone", - "-Wclippy::imprecise_flops", - "-Wclippy::inefficient_to_string", - "-Wclippy::invalid_upcast_comparisons", - "-Wclippy::large_digit_groups", - "-Wclippy::large_stack_arrays", - "-Wclippy::large_types_passed_by_value", - "-Wclippy::let_unit_value", - "-Wclippy::linkedlist", - "-Wclippy::lossy_float_literal", - "-Wclippy::macro_use_imports", - "-Wclippy::manual_ok_or", - "-Wclippy::map_flatten", - "-Wclippy::match_on_vec_items", - "-Wclippy::match_same_arms", - "-Wclippy::match_wildcard_for_single_variants", - "-Wclippy::match_wild_err_arm", - "-Wclippy::mem_forget", - "-Wclippy::mismatched_target_os", - "-Wclippy::missing_enforced_import_renames", - "-Wclippy::mutex_integer", - "-Wclippy::mut_mut", - "-Wclippy::needless_continue", - "-Wclippy::needless_for_each", - "-Wclippy::needless_pass_by_value", - "-Wclippy::option_option", - "-Wclippy::path_buf_push_overwrite", - "-Wclippy::ptr_as_ptr", - "-Wclippy::rc_mutex", - "-Wclippy::ref_option_ref", - "-Wclippy::rest_pat_in_fully_bound_structs", - "-Wclippy::same_functions_in_if_condition", - "-Wclippy::semicolon_if_nothing_returned", - "-Wclippy::single_match_else", - "-Wclippy::string_add", - "-Wclippy::string_add_assign", - "-Wclippy::string_to_string", - "-Wclippy::todo", - "-Wclippy::trait_duplication_in_bounds", - "-Wclippy::unimplemented", - "-Wclippy::unnested_or_patterns", - "-Wclippy::unused_self", - "-Wclippy::useless_transmute", - "-Wclippy::verbose_file_reads", - "-Wclippy::zero_sized_map_values", -] diff --git a/Cargo.toml b/Cargo.toml index 6f792eb..6a051b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,60 @@ resolver = "2" chrono-tz = { version = "0.9.0", default-features = false, features = ["std"] } serde_json = { version = "1.0.117", default-features = false } serde = { version = "1.0.203", features = ["derive"] } + +# use only "allow" and "warn" for lints (both rustc and clippy) +# the xtask CI task will fail on warnings but +# we only want the warnings during local development +[workspace.lints.rust] +# Lint groups are set to warn so new lints are used as they become available +future_incompatible = { level = "warn", priority = -1 } +let_underscore = { level = "warn", priority = -1 } +nonstandard-style = { level = "warn", priority = -1 } +rust_2018_compatibility = { level = "warn", priority = -1 } +rust_2018_idioms = { level = "warn", priority = -1 } +rust_2021_compatibility = { level = "warn", priority = -1 } +unused = { level = "warn", priority = -1 } +warnings = { level = "warn", priority = -1 } + +# 2024 compatibility is allow for now and will be fixed in a near-future PR +rust_2024_compatibility = { level = "allow", priority = -2 } + +# We also warn on a set of individual lints that are ont included in any group +async_fn_in_trait = "warn" +dead_code = "warn" +trivial_casts = "warn" +trivial_numeric_casts = "warn" +unsafe_code = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" +unused_qualifications = "warn" + +[workspace.lints.clippy] +# Lint groups are set to warn so new lints are used as they become available +complexity = { level = "warn", priority = -1 } +correctness = { level = "warn", priority = -1 } +pedantic = { level = "warn", priority = -1 } +perf = { level = "warn", priority = -1 } +style = { level = "warn", priority = -1 } +suspicious = { level = "warn", priority = -1 } + +# These lints are explicitly allowed as they don't provide value for TD. +doc_markdown = "allow" +missing_panics_doc = "allow" +missing_errors_doc = "allow" +map_unwrap_or = "allow" # we prefer to `map(a).unwrap_or(b)` as it's clear what the fallback value is + +# # These lints are allowed, but we want to deny them over time +# default_trait_access = "allow" +# into_iter_without_iter = "allow" +# items_after_statements = "allow" +# large_futures = "allow" +# module_name_repetitions = "allow" +# must_use_candidate = "allow" +# needless_pass_by_value = "allow" +# similar_names = "allow" +# struct_excessive_bools = "allow" +# struct_field_names = "allow" +# too_many_lines = "allow" +# trivially_copy_pass_by_ref = "allow" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 3ccd1b5..b34f689 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -20,3 +20,6 @@ ocpi-tariffs = { version = "0.6.1", path = "../ocpi-tariffs", features = ["ocpi- serde_json.workspace = true serde.workspace = true tabled = { version = "0.15.0" } + +[lints] +workspace = true diff --git a/ocpi-tariffs/Cargo.toml b/ocpi-tariffs/Cargo.toml index 1ca67d3..9446bc6 100644 --- a/ocpi-tariffs/Cargo.toml +++ b/ocpi-tariffs/Cargo.toml @@ -20,3 +20,6 @@ serde.workspace = true [dev-dependencies] serde_json.workspace = true test-each = { version = "0.2.1" } + +[lints] +workspace = true From 3d5994ccbd48a02633c5e77d0743ec8f2d2cb762 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:26:08 +0200 Subject: [PATCH 04/15] cargo fix --- cli/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/error.rs b/cli/src/error.rs index 7d7f1b7..d2f46d3 100644 --- a/cli/src/error.rs +++ b/cli/src/error.rs @@ -9,7 +9,7 @@ pub enum Error { Deserialize { path: String, kind: &'static str, - error: std::io::Error, + error: io::Error, }, Internal(ocpi_tariffs::Error), } @@ -39,7 +39,7 @@ impl Error { pub fn deserialize( path: impl fmt::Display, kind: &'static str, - error: impl Into, + error: impl Into, ) -> Self { Self::Deserialize { path: path.to_string(), From 9a2e40d603061a169788cd89763f59bcaa6bb2aa Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:26:31 +0200 Subject: [PATCH 05/15] cargo clippy --fix --- cli/src/cli.rs | 4 ++-- ocpi-tariffs/src/pricer.rs | 8 ++++---- ocpi-tariffs/src/session.rs | 2 +- ocpi-tariffs/src/tariff.rs | 8 ++++---- ocpi-tariffs/src/types/electricity.rs | 6 +++--- ocpi-tariffs/src/types/money.rs | 16 ++++++++-------- ocpi-tariffs/src/types/time.rs | 4 ++-- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 5179c21..26356e9 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -393,7 +393,7 @@ impl Analyze { let mut time: PeriodTable = PeriodTable::new("Charging Time"); let mut flat: PeriodTable = PeriodTable::new("Flat"); - for period in report.periods.iter() { + for period in &report.periods { let start_time = period.start_date_time.with_timezone(&self.args.timezone); energy.row(&period.dimensions.energy, start_time); @@ -523,7 +523,7 @@ impl Display for UnitDisplay { } impl From<()> for UnitDisplay { - fn from(_: ()) -> Self { + fn from((): ()) -> Self { UnitDisplay } } diff --git a/ocpi-tariffs/src/pricer.rs b/ocpi-tariffs/src/pricer.rs index 029f54e..8261c02 100644 --- a/ocpi-tariffs/src/pricer.rs +++ b/ocpi-tariffs/src/pricer.rs @@ -47,7 +47,7 @@ pub struct Pricer<'a> { impl<'a> Pricer<'a> { /// Create a new pricer instance using the specified [`Cdr`]. - pub fn new(cdr: &'a Cdr) -> Self { + #[must_use] pub fn new(cdr: &'a Cdr) -> Self { Self { cdr, time_zone: None, @@ -65,7 +65,7 @@ impl<'a> Pricer<'a> { /// Directly specify a time zone to use for the calculation. This overrides any time zones in /// the session or any detected time zones if [`Self::detect_time_zone`] is set to true. - pub fn with_time_zone(mut self, time_zone: Tz) -> Self { + #[must_use] pub fn with_time_zone(mut self, time_zone: Tz) -> Self { self.time_zone = Some(time_zone); self @@ -75,7 +75,7 @@ impl<'a> Pricer<'a> { /// is missing. The detection will only succeed if the country has just one time-zone, /// nonetheless there are edge cases where the detection will be incorrect. Only use this /// feature as a fallback when a certain degree of inaccuracy is allowed. - pub fn detect_time_zone(mut self, detect: bool) -> Self { + #[must_use] pub fn detect_time_zone(mut self, detect: bool) -> Self { self.detect_time_zone = detect; self @@ -452,7 +452,7 @@ impl PeriodReport { } /// The total cost of all dimensions in this period. - pub fn cost(&self) -> Option { + #[must_use] pub fn cost(&self) -> Option { [ self.dimensions.time.cost(), self.dimensions.parking_time.cost(), diff --git a/ocpi-tariffs/src/session.rs b/ocpi-tariffs/src/session.rs index 2b0c00f..d918944 100644 --- a/ocpi-tariffs/src/session.rs +++ b/ocpi-tariffs/src/session.rs @@ -169,7 +169,7 @@ impl PeriodData { energy: None, }; - for dimension in period.dimensions.iter() { + for dimension in &period.dimensions { match *dimension { OcpiCdrDimension::MinCurrent(volume) => inst.min_current = Some(volume), OcpiCdrDimension::MaxCurrent(volume) => inst.max_current = Some(volume), diff --git a/ocpi-tariffs/src/tariff.rs b/ocpi-tariffs/src/tariff.rs index f2ad40f..fe69aca 100644 --- a/ocpi-tariffs/src/tariff.rs +++ b/ocpi-tariffs/src/tariff.rs @@ -35,7 +35,7 @@ impl Tariff { pub fn active_components(&self, period: &ChargePeriod) -> PriceComponents { let mut components = PriceComponents::new(); - for tariff_element in self.elements.iter() { + for tariff_element in &self.elements { if !tariff_element.is_active(period) { continue; } @@ -90,7 +90,7 @@ impl TariffElement { let mut components = PriceComponents::new(); - for ocpi_component in ocpi_element.price_components.iter() { + for ocpi_component in &ocpi_element.price_components { let price_component = PriceComponent::new(ocpi_component, element_index); match ocpi_component.component_type { @@ -110,7 +110,7 @@ impl TariffElement { } pub fn is_active(&self, period: &ChargePeriod) -> bool { - for restriction in self.restrictions.iter() { + for restriction in &self.restrictions { if !restriction.instant_validity_exclusive(&period.start_instant) { return false; } @@ -126,7 +126,7 @@ impl TariffElement { // use this in the future to validate if a period is still valid when it ends. #[allow(dead_code)] pub fn is_active_at_end(&self, period: &ChargePeriod) -> bool { - for restriction in self.restrictions.iter() { + for restriction in &self.restrictions { if !restriction.instant_validity_inclusive(&period.end_instant) { return false; } diff --git a/ocpi-tariffs/src/types/electricity.rs b/ocpi-tariffs/src/types/electricity.rs index 65e7826..7717517 100644 --- a/ocpi-tariffs/src/types/electricity.rs +++ b/ocpi-tariffs/src/types/electricity.rs @@ -15,12 +15,12 @@ impl Kwh { } /// Saturating addition - pub fn saturating_add(self, other: Self) -> Self { + #[must_use] pub fn saturating_add(self, other: Self) -> Self { Self(self.0.saturating_add(other.0)) } /// Saturating subtraction - pub fn saturating_sub(self, other: Self) -> Self { + #[must_use] pub fn saturating_sub(self, other: Self) -> Self { Self(self.0.saturating_sub(other.0)) } @@ -36,7 +36,7 @@ impl Kwh { } /// Round this number to the OCPI specified amount of decimals. - pub fn with_scale(self) -> Self { + #[must_use] pub fn with_scale(self) -> Self { Self(self.0.with_scale()) } } diff --git a/ocpi-tariffs/src/types/money.rs b/ocpi-tariffs/src/types/money.rs index 2f5632e..9e3bf1a 100644 --- a/ocpi-tariffs/src/types/money.rs +++ b/ocpi-tariffs/src/types/money.rs @@ -34,7 +34,7 @@ impl Price { } /// Saturating addition. - pub fn saturating_add(self, rhs: Self) -> Self { + #[must_use] pub fn saturating_add(self, rhs: Self) -> Self { Self { excl_vat: self.excl_vat.saturating_add(rhs.excl_vat), incl_vat: match (self.incl_vat, rhs.incl_vat) { @@ -64,37 +64,37 @@ impl Money { } /// Round this number to the OCPI specified amount of decimals. - pub fn with_scale(self) -> Self { + #[must_use] pub fn with_scale(self) -> Self { Self(self.0.with_scale()) } /// Saturating addition - pub fn saturating_add(self, other: Self) -> Self { + #[must_use] pub fn saturating_add(self, other: Self) -> Self { Self(self.0.saturating_add(other.0)) } /// Saturating subtraction - pub fn saturating_sub(self, other: Self) -> Self { + #[must_use] pub fn saturating_sub(self, other: Self) -> Self { Self(self.0.saturating_sub(other.0)) } /// Saturating multiplication - pub fn saturating_mul(self, other: Self) -> Self { + #[must_use] pub fn saturating_mul(self, other: Self) -> Self { Self(self.0.saturating_mul(other.0)) } /// Apply a VAT percentage to this monetary amount. - pub fn apply_vat(self, vat: Vat) -> Self { + #[must_use] pub fn apply_vat(self, vat: Vat) -> Self { Self(self.0.saturating_mul(vat.as_fraction())) } /// Cost of a certain amount of [`Kwh`] with this price. - pub fn kwh_cost(self, kwh: Kwh) -> Self { + #[must_use] pub fn kwh_cost(self, kwh: Kwh) -> Self { Self(self.0.saturating_mul(kwh.into())) } /// Cost of a certain amount of [`HoursDecimal`] with this price. - pub fn time_cost(self, hours: HoursDecimal) -> Self { + #[must_use] pub fn time_cost(self, hours: HoursDecimal) -> Self { Self(self.0.saturating_mul(hours.as_num_hours_number())) } } diff --git a/ocpi-tariffs/src/types/time.rs b/ocpi-tariffs/src/types/time.rs index 30d7239..43a160a 100644 --- a/ocpi-tariffs/src/types/time.rs +++ b/ocpi-tariffs/src/types/time.rs @@ -46,7 +46,7 @@ impl Display for HoursDecimal { let minutes = (duration.num_seconds() / SECS_IN_MIN) % MINS_IN_HOUR; let hours = duration.num_seconds() / (SECS_IN_MIN * MINS_IN_HOUR); - write!(f, "{:0>2}:{:0>2}:{:0>2}", hours, minutes, seconds) + write!(f, "{hours:0>2}:{minutes:0>2}:{seconds:0>2}") } } @@ -74,7 +74,7 @@ impl HoursDecimal { } /// Convert into decimal representation. - pub fn as_num_hours_decimal(&self) -> rust_decimal::Decimal { + #[must_use] pub fn as_num_hours_decimal(&self) -> rust_decimal::Decimal { self.as_num_hours_number().into() } From fa4af20e8d0755d533dcbfc3a081c54ab801c7d4 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:36:59 +0200 Subject: [PATCH 06/15] Fix clippies --- Cargo.toml | 15 ++------------- ocpi-tariffs/src/lib.rs | 1 - ocpi-tariffs/src/pricer.rs | 14 ++++++++++---- ocpi-tariffs/src/types/money.rs | 25 +++++++++++++++++-------- ocpi-tariffs/src/types/time.rs | 7 ++++--- ocpi-tariffs/tests/integration.rs | 1 + 6 files changed, 34 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6a051b2..3e80391 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,16 +58,5 @@ missing_panics_doc = "allow" missing_errors_doc = "allow" map_unwrap_or = "allow" # we prefer to `map(a).unwrap_or(b)` as it's clear what the fallback value is -# # These lints are allowed, but we want to deny them over time -# default_trait_access = "allow" -# into_iter_without_iter = "allow" -# items_after_statements = "allow" -# large_futures = "allow" -# module_name_repetitions = "allow" -# must_use_candidate = "allow" -# needless_pass_by_value = "allow" -# similar_names = "allow" -# struct_excessive_bools = "allow" -# struct_field_names = "allow" -# too_many_lines = "allow" -# trivially_copy_pass_by_ref = "allow" +# These lints are allowed, but we want to deny them over time +module_name_repetitions = "allow" diff --git a/ocpi-tariffs/src/lib.rs b/ocpi-tariffs/src/lib.rs index 8334bd4..c72a4ea 100644 --- a/ocpi-tariffs/src/lib.rs +++ b/ocpi-tariffs/src/lib.rs @@ -1,4 +1,3 @@ -#![deny(missing_docs)] //! # OCPI Tariffs library //! //! Functionality to calculate the (sub)totals of a charge session. Use the diff --git a/ocpi-tariffs/src/pricer.rs b/ocpi-tariffs/src/pricer.rs index 8261c02..a00baaf 100644 --- a/ocpi-tariffs/src/pricer.rs +++ b/ocpi-tariffs/src/pricer.rs @@ -47,7 +47,8 @@ pub struct Pricer<'a> { impl<'a> Pricer<'a> { /// Create a new pricer instance using the specified [`Cdr`]. - #[must_use] pub fn new(cdr: &'a Cdr) -> Self { + #[must_use] + pub fn new(cdr: &'a Cdr) -> Self { Self { cdr, time_zone: None, @@ -57,6 +58,7 @@ impl<'a> Pricer<'a> { } /// Use a list of [`OcpiTariff`]'s for pricing instead of the tariffs found in the [`Cdr`]. + #[must_use] pub fn with_tariffs(mut self, tariffs: impl IntoIterator) -> Self { self.tariffs = Some(tariffs.into_iter().collect()); @@ -65,7 +67,8 @@ impl<'a> Pricer<'a> { /// Directly specify a time zone to use for the calculation. This overrides any time zones in /// the session or any detected time zones if [`Self::detect_time_zone`] is set to true. - #[must_use] pub fn with_time_zone(mut self, time_zone: Tz) -> Self { + #[must_use] + pub fn with_time_zone(mut self, time_zone: Tz) -> Self { self.time_zone = Some(time_zone); self @@ -75,7 +78,8 @@ impl<'a> Pricer<'a> { /// is missing. The detection will only succeed if the country has just one time-zone, /// nonetheless there are edge cases where the detection will be incorrect. Only use this /// feature as a fallback when a certain degree of inaccuracy is allowed. - #[must_use] pub fn detect_time_zone(mut self, detect: bool) -> Self { + #[must_use] + pub fn detect_time_zone(mut self, detect: bool) -> Self { self.detect_time_zone = detect; self @@ -83,6 +87,7 @@ impl<'a> Pricer<'a> { /// Attempt to apply the first applicable tariff to the charge session and build a report /// containing the results. + #[allow(clippy::too_many_lines)] pub fn build_report(self) -> Result { let cdr_tz = self.cdr.cdr_location.time_zone.as_ref(); @@ -452,7 +457,8 @@ impl PeriodReport { } /// The total cost of all dimensions in this period. - #[must_use] pub fn cost(&self) -> Option { + #[must_use] + pub fn cost(&self) -> Option { [ self.dimensions.time.cost(), self.dimensions.parking_time.cost(), diff --git a/ocpi-tariffs/src/types/money.rs b/ocpi-tariffs/src/types/money.rs index 9e3bf1a..b97578b 100644 --- a/ocpi-tariffs/src/types/money.rs +++ b/ocpi-tariffs/src/types/money.rs @@ -26,6 +26,7 @@ impl Price { } /// Round this number to the OCPI specified amount of decimals. + #[must_use] pub fn with_scale(self) -> Self { Self { excl_vat: self.excl_vat.with_scale(), @@ -34,7 +35,8 @@ impl Price { } /// Saturating addition. - #[must_use] pub fn saturating_add(self, rhs: Self) -> Self { + #[must_use] + pub fn saturating_add(self, rhs: Self) -> Self { Self { excl_vat: self.excl_vat.saturating_add(rhs.excl_vat), incl_vat: match (self.incl_vat, rhs.incl_vat) { @@ -64,37 +66,44 @@ impl Money { } /// Round this number to the OCPI specified amount of decimals. - #[must_use] pub fn with_scale(self) -> Self { + #[must_use] + pub fn with_scale(self) -> Self { Self(self.0.with_scale()) } /// Saturating addition - #[must_use] pub fn saturating_add(self, other: Self) -> Self { + #[must_use] + pub fn saturating_add(self, other: Self) -> Self { Self(self.0.saturating_add(other.0)) } /// Saturating subtraction - #[must_use] pub fn saturating_sub(self, other: Self) -> Self { + #[must_use] + pub fn saturating_sub(self, other: Self) -> Self { Self(self.0.saturating_sub(other.0)) } /// Saturating multiplication - #[must_use] pub fn saturating_mul(self, other: Self) -> Self { + #[must_use] + pub fn saturating_mul(self, other: Self) -> Self { Self(self.0.saturating_mul(other.0)) } /// Apply a VAT percentage to this monetary amount. - #[must_use] pub fn apply_vat(self, vat: Vat) -> Self { + #[must_use] + pub fn apply_vat(self, vat: Vat) -> Self { Self(self.0.saturating_mul(vat.as_fraction())) } /// Cost of a certain amount of [`Kwh`] with this price. - #[must_use] pub fn kwh_cost(self, kwh: Kwh) -> Self { + #[must_use] + pub fn kwh_cost(self, kwh: Kwh) -> Self { Self(self.0.saturating_mul(kwh.into())) } /// Cost of a certain amount of [`HoursDecimal`] with this price. - #[must_use] pub fn time_cost(self, hours: HoursDecimal) -> Self { + #[must_use] + pub fn time_cost(self, hours: HoursDecimal) -> Self { Self(self.0.saturating_mul(hours.as_num_hours_number())) } } diff --git a/ocpi-tariffs/src/types/time.rs b/ocpi-tariffs/src/types/time.rs index 43a160a..d2ce1f9 100644 --- a/ocpi-tariffs/src/types/time.rs +++ b/ocpi-tariffs/src/types/time.rs @@ -74,7 +74,8 @@ impl HoursDecimal { } /// Convert into decimal representation. - #[must_use] pub fn as_num_hours_decimal(&self) -> rust_decimal::Decimal { + #[must_use] + pub fn as_num_hours_decimal(&self) -> rust_decimal::Decimal { self.as_num_hours_number().into() } @@ -100,12 +101,12 @@ impl HoursDecimal { )) } - /// Saturating subtraction. + #[must_use] pub fn saturating_sub(self, other: Self) -> Self { Self(self.0.checked_sub(&other.0).unwrap_or_else(Duration::zero)) } - /// Saturating addition. + #[must_use] pub fn saturating_add(self, other: Self) -> Self { Self( self.0 diff --git a/ocpi-tariffs/tests/integration.rs b/ocpi-tariffs/tests/integration.rs index 56896e0..ab2fae8 100644 --- a/ocpi-tariffs/tests/integration.rs +++ b/ocpi-tariffs/tests/integration.rs @@ -5,6 +5,7 @@ use ocpi_tariffs::{ }; use std::path::PathBuf; +#[allow(clippy::needless_pass_by_value)] #[test_each::file(glob = "ocpi-tariffs/test_data/*/cdr*.json", name(segments = 2))] fn test_json(cdr: &str, path: PathBuf) { let tariff = std::fs::read_to_string(path.parent().unwrap().join("tariff.json")).unwrap(); From 6d3b22bd28e470b2ad80b5ee3f39c866849c892f Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:42:38 +0200 Subject: [PATCH 07/15] Rm whack support --- scripts/clean_build.sh | 16 ---------------- whack.toml | 5 ----- 2 files changed, 21 deletions(-) delete mode 100644 scripts/clean_build.sh delete mode 100644 whack.toml diff --git a/scripts/clean_build.sh b/scripts/clean_build.sh deleted file mode 100644 index 0aad87f..0000000 --- a/scripts/clean_build.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -set -e - -start=$(date -Iseconds -u) -host_name=$(hostname) -echo "Starting build at: ${start} on ${host_name}" - -for dir in "${BUILD_OUTPUT}/debug/build" \ - "${BUILD_OUTPUT}/debug/deps" \ - "${BUILD_OUTPUT}/debug/incremental" -do - if [ -d "${dir}" ] ; then - find "${dir}" ! -newerct '15 days ago' -d -exec rm -rv {} \; - fi -done diff --git a/whack.toml b/whack.toml deleted file mode 100644 index 6919d4a..0000000 --- a/whack.toml +++ /dev/null @@ -1,5 +0,0 @@ -worker_dependencies = ["rust"] - -[scripts] -run_tests = "scripts/ci.sh" -clean_build = "scripts/clean_build.sh" From 38cb3028aa67c5aaa71ef9c0ee61235f9afaa954 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:44:27 +0200 Subject: [PATCH 08/15] Adjust `ci` script for local build use --- scripts/ci.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/ci.sh b/scripts/ci.sh index bbc0c30..48e6ce9 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -2,13 +2,8 @@ set -e -start=$(date -Iseconds -u) -host_name=$(hostname) -echo "Starting build at: ${start} on ${host_name}" - -export CARGO_TARGET_DIR="${BUILD_OUTPUT}" +export CARGO_TARGET_DIR="target" export RUST_BACKTRACE="full" -export PATH="/var/whack/.cargo/bin:$PATH" cargo deny --workspace -L info check cargo check From f12bd9a7c65c49cb2a4255799719642ef7ace2e1 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:51:03 +0200 Subject: [PATCH 09/15] Adjust lints and fix clippies --- Cargo.toml | 7 +++---- ocpi-tariffs/src/ocpi/v211/tariff.rs | 16 ++++++++-------- ocpi-tariffs/src/ocpi/v221/tariff.rs | 16 ++++++++-------- ocpi-tariffs/src/types/money.rs | 2 +- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3e80391..19104ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,11 +52,10 @@ perf = { level = "warn", priority = -1 } style = { level = "warn", priority = -1 } suspicious = { level = "warn", priority = -1 } -# These lints are explicitly allowed as they don't provide value for TD. -doc_markdown = "allow" -missing_panics_doc = "allow" -missing_errors_doc = "allow" +# These lints are explicitly allowed. +missing_errors_doc = "allow" # the Error type is self documenting map_unwrap_or = "allow" # we prefer to `map(a).unwrap_or(b)` as it's clear what the fallback value is # These lints are allowed, but we want to deny them over time +missing_panics_doc = "allow" module_name_repetitions = "allow" diff --git a/ocpi-tariffs/src/ocpi/v211/tariff.rs b/ocpi-tariffs/src/ocpi/v211/tariff.rs index 47710f4..0928826 100644 --- a/ocpi-tariffs/src/ocpi/v211/tariff.rs +++ b/ocpi-tariffs/src/ocpi/v211/tariff.rs @@ -41,10 +41,10 @@ pub struct OcpiPriceComponent { /// Price per unit (excluding VAT) for this tariff dimension pub price: Money, - /// Minimum amount to be billed. This unit will be billed in this step_size - /// blocks. For example: if type is time and step_size is 300, then time will + /// Minimum amount to be billed. This unit will be billed in this `step_size` + /// blocks. For example: if type is time and `step_size` is 300, then time will /// be billed in blocks of 5 minutes, so if 6 minutes is used, 10 minutes (2 - /// blocks of step_size) will be billed + /// blocks of `step_size`) will be billed pub step_size: u64, } @@ -62,13 +62,13 @@ pub struct OcpiTariffElement { #[derive(Debug, Copy, PartialEq, Eq, Clone, Hash, Deserialize, Serialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum TariffDimensionType { - /// Defined in kWh, step_size multiplier: 1 Wh + /// Defined in kWh, `step_size` multiplier: 1 Wh Energy, - /// Flat fee, no unit for step_size + /// Flat fee, no unit for `step_size` Flat, - /// Time not charging: defined in hours, step_size multiplier: 1 second + /// Time not charging: defined in hours, `step_size` multiplier: 1 second ParkingTime, - /// Time charging: defined in hours, step_size multiplier: 1 second + /// Time charging: defined in hours, `step_size` multiplier: 1 second Time, } @@ -80,7 +80,7 @@ pub struct OcpiTariffRestriction { pub start_time: Option, /// End time of day, for example 19:45, valid until this - /// time of the day. Same syntax as start_time + /// time of the day. Same syntax as `start_time` pub end_time: Option, /// Start date, for example: 2015-12-24, valid from this day diff --git a/ocpi-tariffs/src/ocpi/v221/tariff.rs b/ocpi-tariffs/src/ocpi/v221/tariff.rs index b91c13c..ad099d7 100644 --- a/ocpi-tariffs/src/ocpi/v221/tariff.rs +++ b/ocpi-tariffs/src/ocpi/v221/tariff.rs @@ -48,10 +48,10 @@ pub struct OcpiPriceComponent { /// Optionally specify a VAT percentage for this component. pub vat: CompatibilityVat, - /// Minimum amount to be billed. This unit will be billed in this step_size - /// blocks. For example: if type is time and step_size is 300, then time will + /// Minimum amount to be billed. This unit will be billed in this `step_size` + /// blocks. For example: if type is time and `step_size` is 300, then time will /// be billed in blocks of 5 minutes, so if 6 minutes is used, 10 minutes (2 - /// blocks of step_size) will be billed + /// blocks of `step_size`) will be billed pub step_size: u64, } @@ -104,13 +104,13 @@ pub struct OcpiTariffElement { #[derive(Debug, Copy, PartialEq, Eq, Clone, Hash, Deserialize, Serialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum TariffDimensionType { - /// Defined in kWh, step_size multiplier: 1 Wh + /// Defined in kWh, `step_size` multiplier: 1 Wh Energy, - /// Flat fee, no unit for step_size + /// Flat fee, no unit for `step_size` Flat, - /// Time not charging: defined in hours, step_size multiplier: 1 second + /// Time not charging: defined in hours, `step_size` multiplier: 1 second ParkingTime, - /// Time charging: defined in hours, step_size multiplier: 1 second + /// Time charging: defined in hours, `step_size` multiplier: 1 second Time, } @@ -122,7 +122,7 @@ pub struct OcpiTariffRestriction { pub start_time: Option, /// End time of day, for example 19:45, valid until this - /// time of the day. Same syntax as start_time + /// time of the day. Same syntax as `start_time` pub end_time: Option, /// Start date, for example: 2015-12-24, valid from this day diff --git a/ocpi-tariffs/src/types/money.rs b/ocpi-tariffs/src/types/money.rs index b97578b..d862857 100644 --- a/ocpi-tariffs/src/types/money.rs +++ b/ocpi-tariffs/src/types/money.rs @@ -11,7 +11,7 @@ pub struct Price { #[serde(default)] /// The price including VAT. /// - /// If no vat is applicable this value will be equal to the excl_vat. + /// If no vat is applicable this value will be equal to the `excl_vat`. /// /// If no vat could be determined (tariff is 2.1.1) this value will be `None`. pub incl_vat: Option, From f02a6fa6534add85871999a00efed0d26c2b5c0c Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:57:38 +0200 Subject: [PATCH 10/15] cargo fmt --- ocpi-tariffs/src/types/electricity.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ocpi-tariffs/src/types/electricity.rs b/ocpi-tariffs/src/types/electricity.rs index 7717517..7f7d63a 100644 --- a/ocpi-tariffs/src/types/electricity.rs +++ b/ocpi-tariffs/src/types/electricity.rs @@ -15,12 +15,14 @@ impl Kwh { } /// Saturating addition - #[must_use] pub fn saturating_add(self, other: Self) -> Self { + #[must_use] + pub fn saturating_add(self, other: Self) -> Self { Self(self.0.saturating_add(other.0)) } /// Saturating subtraction - #[must_use] pub fn saturating_sub(self, other: Self) -> Self { + #[must_use] + pub fn saturating_sub(self, other: Self) -> Self { Self(self.0.saturating_sub(other.0)) } @@ -36,7 +38,8 @@ impl Kwh { } /// Round this number to the OCPI specified amount of decimals. - #[must_use] pub fn with_scale(self) -> Self { + #[must_use] + pub fn with_scale(self) -> Self { Self(self.0.with_scale()) } } From 70ac0f6fc8e7d3b24343fd9af2cc4c5b0764d3b2 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 11:58:51 +0200 Subject: [PATCH 11/15] Bring `script/ci.sh` in line with `.github/workflow/rust.yml` --- scripts/ci.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/ci.sh b/scripts/ci.sh index 48e6ce9..186aca3 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -5,8 +5,9 @@ set -e export CARGO_TARGET_DIR="target" export RUST_BACKTRACE="full" -cargo deny --workspace -L info check -cargo check -cargo clippy -cargo doc --workspace --no-deps +cargo deny --workspace --all-features -L info check +cargo check --workspace --all-features +cargo fmt --all --check +cargo clippy --workspace --all-features --all-targets +cargo doc --workspace --all-features --no-deps --document-private-items cargo test From 57fa3166c42b25e4032b3c1bf81929d59fadd0a7 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 12:03:24 +0200 Subject: [PATCH 12/15] Bring `script/ci.sh` in line with `.github/workflow/rust.yml` --- scripts/ci.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ci.sh b/scripts/ci.sh index 186aca3..8896a0e 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -6,8 +6,8 @@ export CARGO_TARGET_DIR="target" export RUST_BACKTRACE="full" cargo deny --workspace --all-features -L info check -cargo check --workspace --all-features +cargo check --workspace --all-features --verbose cargo fmt --all --check cargo clippy --workspace --all-features --all-targets cargo doc --workspace --all-features --no-deps --document-private-items -cargo test +cargo test --workspace --all-features --verbose From b323204705c7606d047c855e9ba336f0079fd573 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 12:10:05 +0200 Subject: [PATCH 13/15] Deny clippy warnings during CI --- .github/workflows/rust.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f251587..520292d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,7 +30,7 @@ jobs: timeout-minutes: 45 steps: - uses: actions/checkout@v3 - - run: cargo clippy --workspace --all-targets --all-features + - run: cargo clippy --workspace --all-targets --all-features -- -Dwarnings format: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 19104ae..2517f05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ serde_json = { version = "1.0.117", default-features = false } serde = { version = "1.0.203", features = ["derive"] } # use only "allow" and "warn" for lints (both rustc and clippy) -# the xtask CI task will fail on warnings but +# the Githud CI task will fail on warnings but # we only want the warnings during local development [workspace.lints.rust] # Lint groups are set to warn so new lints are used as they become available From ea521c43f87b7cdd9f89f8841f30910cf949f35d Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 2 Oct 2024 12:10:43 +0200 Subject: [PATCH 14/15] Fix typo --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2517f05..fb2aab7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ serde_json = { version = "1.0.117", default-features = false } serde = { version = "1.0.203", features = ["derive"] } # use only "allow" and "warn" for lints (both rustc and clippy) -# the Githud CI task will fail on warnings but +# the Github CI task will fail on warnings but # we only want the warnings during local development [workspace.lints.rust] # Lint groups are set to warn so new lints are used as they become available From 7ff97a58a3063912a597218dc88703d32d08b8cc Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 4 Oct 2024 13:12:33 +0200 Subject: [PATCH 15/15] Fix clippies --- cli/src/cli.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 77b3d9c..f12c01f 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -180,6 +180,7 @@ pub struct Validate { } impl Validate { + #[allow(clippy::too_many_lines)] fn run(self) -> Result<()> { let (report, cdr, _) = self.args.load_all()?; @@ -314,7 +315,7 @@ impl Validate { table.retain_rows(|v| !v[1].is_empty() || !v[2].is_empty()); - println!("{}", table); + println!("{table}"); if !is_valid { println!( @@ -323,13 +324,13 @@ impl Validate { ); exit(1); - } else { - println!( - "Calculation {} all totals in the CDR.\n", - style("matches").green().bold() - ); } + println!( + "Calculation {} all totals in the CDR.\n", + style("matches").green().bold() + ); + Ok(()) } } @@ -365,7 +366,7 @@ impl Analyze { "Flat", ]); - for period in report.periods.iter() { + for period in &report.periods { let start_time = period.start_date_time.with_timezone(&time_zone); let dim = &period.dimensions; @@ -379,7 +380,7 @@ impl Analyze { ]); table.row(&[ - "".to_string(), + String::new(), "Price".to_string(), to_string_or_default(dim.energy.price.map(|p| p.price)), to_string_or_default(dim.time.price.map(|p| p.price)), @@ -396,11 +397,11 @@ impl Analyze { report.total_energy.to_string(), report.total_time.to_string(), report.total_parking_time.to_string(), - "".to_string(), + String::new(), ]); table.row(&[ - "".to_string(), + String::new(), "Price".to_string(), to_string_or_default(report.total_energy_cost.map(|p| p.excl_vat)), to_string_or_default(report.total_time_cost.map(|p| p.excl_vat)), @@ -408,7 +409,7 @@ impl Analyze { to_string_or_default(report.total_fixed_cost.map(|p| p.excl_vat)), ]); - println!("{}", table); + println!("{table}"); Ok(()) } @@ -499,7 +500,7 @@ impl Display for Table { write!(f, "|")?; for (value, &width) in row.iter().zip(&self.widths) { - write!(f, " {0: <1$} |", value, width)?; + write!(f, " {value: