From ae8402634abce9fa9cd594768bb17e25c0679a8f Mon Sep 17 00:00:00 2001 From: Filipe Rodrigues Date: Wed, 9 Sep 2020 12:12:08 +0100 Subject: [PATCH] Turned various functions in `util` and `io` `const`. Added missing `Sub` and `SubAssign` implementations to `io::address::Real`. Added `from_u64` and `as_u64` to both address types in `io`. --- src/io/address/data.rs | 17 +++++++++----- src/io/address/real.rs | 50 ++++++++++++++++++++++++++++++++++-------- src/lib.rs | 8 ++++--- src/util.rs | 9 +++++--- 4 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/io/address/data.rs b/src/io/address/data.rs index 15aae45..dabce2b 100644 --- a/src/io/address/data.rs +++ b/src/io/address/data.rs @@ -15,23 +15,28 @@ use crate::{ pub struct Data(u64); impl Data { - /// Constructs a data address from it's `u64` representation + /// Creates a data address from a `u64` #[must_use] pub const fn from_u64(address: u64) -> Self { Self(address) } + /// Returns this address as a `u64` + #[must_use] + pub const fn as_u64(self) -> u64 { + self.0 + } + /// Returns the sector associated with this address #[must_use] - #[allow(clippy::integer_division)] // We want to get the whole division - pub fn sector(self) -> u64 { - u64::from(self) / Real::DATA_BYTE_SIZE + pub const fn sector(self) -> u64 { + self.as_u64() / Real::DATA_BYTE_SIZE } /// Returns the offset into the data section of this address #[must_use] - pub fn offset(self) -> u64 { - u64::from(self) % Real::DATA_BYTE_SIZE + pub const fn offset(self) -> u64 { + self.as_u64() % Real::DATA_BYTE_SIZE } } diff --git a/src/io/address/real.rs b/src/io/address/real.rs index 6435138..035e14b 100644 --- a/src/io/address/real.rs +++ b/src/io/address/real.rs @@ -30,28 +30,39 @@ impl Real { } impl Real { + /// Creates a real address from a `u64` + #[must_use] + pub const fn from_u64(address: u64) -> Self { + Self(address) + } + + /// Returns this address as a `u64` + #[must_use] + pub const fn as_u64(self) -> u64 { + self.0 + } + /// Returns the real sector associated with this address #[must_use] - #[allow(clippy::integer_division)] // We want to get the whole division - pub fn sector(self) -> u64 { - u64::from(self) / Self::SECTOR_BYTE_SIZE + pub const fn sector(self) -> u64 { + self.as_u64() / Self::SECTOR_BYTE_SIZE } /// Returns the offset into the sector of this address #[must_use] - pub fn offset(self) -> u64 { - u64::from(self) % Self::SECTOR_BYTE_SIZE + pub const fn offset(self) -> u64 { + self.as_u64() % Self::SECTOR_BYTE_SIZE } /// Returns the address of the end of the data section in this sector. #[must_use] - pub fn data_section_end(self) -> Self { + pub const fn data_section_end(self) -> Self { // Get the sector let real_sector = self.sector(); // The end of the real data section is after the header and data sections #[rustfmt::skip] - Self::from( + Self::from_u64( Self::SECTOR_BYTE_SIZE * real_sector + // Beginning of sector Self::HEADER_BYTE_SIZE + // Skip Header Self:: DATA_BYTE_SIZE, // Skip Data @@ -60,9 +71,11 @@ impl Real { /// Checks if this address is within the real data section #[must_use] - pub fn in_data_section(self) -> bool { + pub const fn in_data_section(self) -> bool { // If our offset is within the data range - Self::DATA_RANGE.contains(&self.offset()) + // TODO: Replace with `Self::DATA_RANGE.contains(&self.offset())` once it's `const`. + let offset = self.offset(); + offset >= Self::DATA_RANGE.start && offset < Self::DATA_RANGE.end } } @@ -82,6 +95,25 @@ impl std::ops::AddAssign for Real { } } +// Real - Offset +impl std::ops::Sub for Real { + type Output = Self; + + fn sub(self, offset: i64) -> Self { + if offset == i64::MIN { + panic!("Unable to offset `i64::MIN`") + } + Self::from(signed_offset(self.into(), -offset)) + } +} + +// Real += Offset +impl std::ops::SubAssign for Real { + fn sub_assign(&mut self, offset: i64) { + *self = *self - offset; + } +} + // Real - Real impl std::ops::Sub for Real { type Output = i64; diff --git a/src/lib.rs b/src/lib.rs index 3750e1e..d06cdf2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,9 @@ stmt_expr_attributes, unwrap_infallible, external_doc, - format_args_capture + format_args_capture, + const_fn, + const_panic )] // Lints #![warn(clippy::restriction, clippy::pedantic, clippy::nursery)] @@ -72,8 +74,8 @@ // In the future, this lint should be removed globally and only enabled for modules which // actually require the use of it. #![allow(clippy::module_inception, clippy::module_name_repetitions)] -// Banning arithmetic is too strict for this project -#![allow(clippy::integer_arithmetic)] +// We use integer arithmetic and operations with the correct intent +#![allow(clippy::integer_arithmetic, clippy::integer_division)] // We prefer using match ergonomic where possible #![allow(clippy::pattern_type_mismatch)] // False positives: diff --git a/src/util.rs b/src/util.rs index 06b5fa8..5f40aa1 100644 --- a/src/util.rs +++ b/src/util.rs @@ -21,7 +21,7 @@ pub use array_split::{array_split, array_split_mut}; /// If the result would not fit into a `i64`, a panic occurs. #[allow(clippy::as_conversions)] // We check every operation #[allow(clippy::panic)] // Rust panics on failed arithmetic operations by default -pub fn abs_diff(a: u64, b: u64) -> i64 { +pub const fn abs_diff(a: u64, b: u64) -> i64 { let diff = if a > b { a - b } else { b - a }; if diff > i64::MAX as u64 { @@ -42,11 +42,14 @@ pub fn abs_diff(a: u64, b: u64) -> i64 { #[allow(clippy::as_conversions)] // We check every operation #[allow(clippy::panic)] // Rust panics on failed arithmetic operations by default #[allow(clippy::cast_sign_loss)] // We've verify it's positive -pub fn signed_offset(a: u64, b: i64) -> u64 { +pub const fn signed_offset(a: u64, b: i64) -> u64 { // If `b` is positive, check for overflows. Else check for underflows if b > 0 { // Note: Cast is safe, as a positive `i64` fits into a `u64`. - a.checked_add(b as u64).expect("Overflow evaluating `u64 + i64`") + match a.checked_add(b as u64) { + Some(res) => res, + None => panic!("Overflow evaluating `u64 + i64`"), + } } else { // Note: On `i64::MIN`, `-b` would overflow if b == i64::MIN || a < (-b) as u64 {