mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-03 12:54:27 +00:00
Remove safe_arith and import from crates.io (#8191)
Use the recently published `safe_arith` and remove it from Lighthouse https://crates.io/crates/safe_arith Co-Authored-By: Mac L <mjladson@pm.me>
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -2162,7 +2162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "18e4fdb82bd54a12e42fb58a800dcae6b9e13982238ce2296dc3570b92148e1f"
|
checksum = "18e4fdb82bd54a12e42fb58a800dcae6b9e13982238ce2296dc3570b92148e1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"syn 1.0.109",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7374,7 +7374,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"itertools 0.10.5",
|
"itertools 0.14.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
@@ -8269,6 +8269,8 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "safe_arith"
|
name = "safe_arith"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b147bb6111014916d3ef9d4c85173124a8e12193a67f6176d67244afd558d6c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "salsa20"
|
name = "salsa20"
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ members = [
|
|||||||
"consensus/int_to_bytes",
|
"consensus/int_to_bytes",
|
||||||
"consensus/merkle_proof",
|
"consensus/merkle_proof",
|
||||||
"consensus/proto_array",
|
"consensus/proto_array",
|
||||||
"consensus/safe_arith",
|
|
||||||
"consensus/state_processing",
|
"consensus/state_processing",
|
||||||
"consensus/swap_or_not_shuffle",
|
"consensus/swap_or_not_shuffle",
|
||||||
"consensus/types",
|
"consensus/types",
|
||||||
@@ -225,7 +224,7 @@ ring = "0.17"
|
|||||||
rpds = "0.11"
|
rpds = "0.11"
|
||||||
rusqlite = { version = "0.28", features = ["bundled"] }
|
rusqlite = { version = "0.28", features = ["bundled"] }
|
||||||
rust_eth_kzg = "0.9"
|
rust_eth_kzg = "0.9"
|
||||||
safe_arith = { path = "consensus/safe_arith" }
|
safe_arith = "0.1"
|
||||||
sensitive_url = { path = "common/sensitive_url" }
|
sensitive_url = { path = "common/sensitive_url" }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "safe_arith"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Michael Sproul <michael@sigmaprime.io>"]
|
|
||||||
edition = { workspace = true }
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
use crate::{Result, SafeArith};
|
|
||||||
|
|
||||||
/// Extension trait for iterators, providing a safe replacement for `sum`.
|
|
||||||
pub trait SafeArithIter<T> {
|
|
||||||
fn safe_sum(self) -> Result<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, T> SafeArithIter<T> for I
|
|
||||||
where
|
|
||||||
I: Iterator<Item = T> + Sized,
|
|
||||||
T: SafeArith,
|
|
||||||
{
|
|
||||||
fn safe_sum(mut self) -> Result<T> {
|
|
||||||
self.try_fold(T::ZERO, |acc, x| acc.safe_add(x))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use crate::ArithError;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn empty_sum() {
|
|
||||||
let v: Vec<u64> = vec![];
|
|
||||||
assert_eq!(v.into_iter().safe_sum(), Ok(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unsigned_sum_small() {
|
|
||||||
let arr = [400u64, 401, 402, 403, 404, 405, 406];
|
|
||||||
assert_eq!(
|
|
||||||
arr.iter().copied().safe_sum().unwrap(),
|
|
||||||
arr.iter().copied().sum()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unsigned_sum_overflow() {
|
|
||||||
let v = vec![u64::MAX, 1];
|
|
||||||
assert_eq!(v.into_iter().safe_sum(), Err(ArithError::Overflow));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn signed_sum_small() {
|
|
||||||
let v = vec![-1i64, -2i64, -3i64, 3, 2, 1];
|
|
||||||
assert_eq!(v.into_iter().safe_sum(), Ok(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn signed_sum_overflow_above() {
|
|
||||||
let v = vec![1, 2, 3, 4, i16::MAX, 0, 1, 2, 3];
|
|
||||||
assert_eq!(v.into_iter().safe_sum(), Err(ArithError::Overflow));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn signed_sum_overflow_below() {
|
|
||||||
let v = vec![i16::MIN, -1];
|
|
||||||
assert_eq!(v.into_iter().safe_sum(), Err(ArithError::Overflow));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn signed_sum_almost_overflow() {
|
|
||||||
let arr = [i64::MIN, 1, -1i64, i64::MAX, i64::MAX, 1];
|
|
||||||
assert_eq!(
|
|
||||||
arr.iter().copied().safe_sum().unwrap(),
|
|
||||||
arr.iter().copied().sum()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
//! Library for safe arithmetic on integers, avoiding overflow and division by zero.
|
|
||||||
mod iter;
|
|
||||||
|
|
||||||
pub use iter::SafeArithIter;
|
|
||||||
|
|
||||||
/// Error representing the failure of an arithmetic operation.
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
pub enum ArithError {
|
|
||||||
Overflow,
|
|
||||||
DivisionByZero,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, ArithError>;
|
|
||||||
|
|
||||||
macro_rules! assign_method {
|
|
||||||
($name:ident, $op:ident, $doc_op:expr) => {
|
|
||||||
assign_method!($name, $op, Self, $doc_op);
|
|
||||||
};
|
|
||||||
($name:ident, $op:ident, $rhs_ty:ty, $doc_op:expr) => {
|
|
||||||
#[doc = "Safe variant of `"]
|
|
||||||
#[doc = $doc_op]
|
|
||||||
#[doc = "`."]
|
|
||||||
#[inline]
|
|
||||||
fn $name(&mut self, other: $rhs_ty) -> Result<()> {
|
|
||||||
*self = self.$op(other)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait providing safe arithmetic operations for built-in types.
|
|
||||||
pub trait SafeArith<Rhs = Self>: Sized + Copy {
|
|
||||||
const ZERO: Self;
|
|
||||||
const ONE: Self;
|
|
||||||
|
|
||||||
/// Safe variant of `+` that guards against overflow.
|
|
||||||
fn safe_add(&self, other: Rhs) -> Result<Self>;
|
|
||||||
|
|
||||||
/// Safe variant of `-` that guards against overflow.
|
|
||||||
fn safe_sub(&self, other: Rhs) -> Result<Self>;
|
|
||||||
|
|
||||||
/// Safe variant of `*` that guards against overflow.
|
|
||||||
fn safe_mul(&self, other: Rhs) -> Result<Self>;
|
|
||||||
|
|
||||||
/// Safe variant of `/` that guards against division by 0.
|
|
||||||
fn safe_div(&self, other: Rhs) -> Result<Self>;
|
|
||||||
|
|
||||||
/// Safe variant of `%` that guards against division by 0.
|
|
||||||
fn safe_rem(&self, other: Rhs) -> Result<Self>;
|
|
||||||
|
|
||||||
/// Safe variant of `<<` that guards against overflow.
|
|
||||||
fn safe_shl(&self, other: u32) -> Result<Self>;
|
|
||||||
|
|
||||||
/// Safe variant of `>>` that guards against overflow.
|
|
||||||
fn safe_shr(&self, other: u32) -> Result<Self>;
|
|
||||||
|
|
||||||
assign_method!(safe_add_assign, safe_add, Rhs, "+=");
|
|
||||||
assign_method!(safe_sub_assign, safe_sub, Rhs, "-=");
|
|
||||||
assign_method!(safe_mul_assign, safe_mul, Rhs, "*=");
|
|
||||||
assign_method!(safe_div_assign, safe_div, Rhs, "/=");
|
|
||||||
assign_method!(safe_rem_assign, safe_rem, Rhs, "%=");
|
|
||||||
assign_method!(safe_shl_assign, safe_shl, u32, "<<=");
|
|
||||||
assign_method!(safe_shr_assign, safe_shr, u32, ">>=");
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_safe_arith {
|
|
||||||
($typ:ty) => {
|
|
||||||
impl SafeArith for $typ {
|
|
||||||
const ZERO: Self = 0;
|
|
||||||
const ONE: Self = 1;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn safe_add(&self, other: Self) -> Result<Self> {
|
|
||||||
self.checked_add(other).ok_or(ArithError::Overflow)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn safe_sub(&self, other: Self) -> Result<Self> {
|
|
||||||
self.checked_sub(other).ok_or(ArithError::Overflow)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn safe_mul(&self, other: Self) -> Result<Self> {
|
|
||||||
self.checked_mul(other).ok_or(ArithError::Overflow)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn safe_div(&self, other: Self) -> Result<Self> {
|
|
||||||
self.checked_div(other).ok_or(ArithError::DivisionByZero)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn safe_rem(&self, other: Self) -> Result<Self> {
|
|
||||||
self.checked_rem(other).ok_or(ArithError::DivisionByZero)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn safe_shl(&self, other: u32) -> Result<Self> {
|
|
||||||
self.checked_shl(other).ok_or(ArithError::Overflow)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn safe_shr(&self, other: u32) -> Result<Self> {
|
|
||||||
self.checked_shr(other).ok_or(ArithError::Overflow)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_safe_arith!(u8);
|
|
||||||
impl_safe_arith!(u16);
|
|
||||||
impl_safe_arith!(u32);
|
|
||||||
impl_safe_arith!(u64);
|
|
||||||
impl_safe_arith!(usize);
|
|
||||||
impl_safe_arith!(i8);
|
|
||||||
impl_safe_arith!(i16);
|
|
||||||
impl_safe_arith!(i32);
|
|
||||||
impl_safe_arith!(i64);
|
|
||||||
impl_safe_arith!(isize);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn basic() {
|
|
||||||
let x = 10u32;
|
|
||||||
let y = 11;
|
|
||||||
assert_eq!(x.safe_add(y), Ok(x + y));
|
|
||||||
assert_eq!(y.safe_sub(x), Ok(y - x));
|
|
||||||
assert_eq!(x.safe_mul(y), Ok(x * y));
|
|
||||||
assert_eq!(x.safe_div(y), Ok(x / y));
|
|
||||||
assert_eq!(x.safe_rem(y), Ok(x % y));
|
|
||||||
|
|
||||||
assert_eq!(x.safe_shl(1), Ok(x << 1));
|
|
||||||
assert_eq!(x.safe_shr(1), Ok(x >> 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn mutate() {
|
|
||||||
let mut x = 0u8;
|
|
||||||
x.safe_add_assign(2).unwrap();
|
|
||||||
assert_eq!(x, 2);
|
|
||||||
x.safe_sub_assign(1).unwrap();
|
|
||||||
assert_eq!(x, 1);
|
|
||||||
x.safe_shl_assign(1).unwrap();
|
|
||||||
assert_eq!(x, 2);
|
|
||||||
x.safe_mul_assign(3).unwrap();
|
|
||||||
assert_eq!(x, 6);
|
|
||||||
x.safe_div_assign(4).unwrap();
|
|
||||||
assert_eq!(x, 1);
|
|
||||||
x.safe_shr_assign(1).unwrap();
|
|
||||||
assert_eq!(x, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn errors() {
|
|
||||||
assert!(u32::MAX.safe_add(1).is_err());
|
|
||||||
assert!(u32::MIN.safe_sub(1).is_err());
|
|
||||||
assert!(u32::MAX.safe_mul(2).is_err());
|
|
||||||
assert!(u32::MAX.safe_div(0).is_err());
|
|
||||||
assert!(u32::MAX.safe_rem(0).is_err());
|
|
||||||
assert!(u32::MAX.safe_shl(32).is_err());
|
|
||||||
assert!(u32::MAX.safe_shr(32).is_err());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user