Merge rust-bitcoin/rust-bitcoin#4557: Move CheckedSum and add Weight
9dac4d69e0
Implement CheckedSum for Weight iterator (yancy)0dbcd09bbc
Move CheckedSum trait to crate root (yancy) Pull request description: * Move CheckedSum to the crate root so that other types can be added * Add Weight to CheckedSum ACKs for top commit: tcharding: ACK9dac4d69e0
apoelstra: ACK 9dac4d69e0f142e9a2dc4b61ea49365a8cae3f4b; successfully ran local tests Tree-SHA512: 3e4b7f79074e23493ccd17a026542081f0d7a811f4f35edb7994ada95bf414a166531f142ad4986d27fcec448209b2ffa56813b495b5df6b6e8fcd589392e0c1
This commit is contained in:
commit
0064ad67a6
|
@ -204,14 +204,15 @@ pub mod amount {
|
||||||
|
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
pub use units::CheckedSum;
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
pub use units::amount::serde;
|
||||||
pub use units::amount::{
|
pub use units::amount::{
|
||||||
Amount, CheckedSum, Denomination, Display, InvalidCharacterError, MissingDenominationError,
|
Amount, Denomination, Display, InvalidCharacterError, MissingDenominationError,
|
||||||
MissingDigitsError, OutOfRangeError, ParseAmountError, ParseDenominationError, ParseError,
|
MissingDigitsError, OutOfRangeError, ParseAmountError, ParseDenominationError, ParseError,
|
||||||
PossiblyConfusingDenominationError, SignedAmount, TooPreciseError,
|
PossiblyConfusingDenominationError, SignedAmount, TooPreciseError,
|
||||||
UnknownDenominationError,
|
UnknownDenominationError,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
pub use units::amount::serde;
|
|
||||||
|
|
||||||
impl Decodable for Amount {
|
impl Decodable for Amount {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -26,6 +26,7 @@ use core::str::FromStr;
|
||||||
use arbitrary::{Arbitrary, Unstructured};
|
use arbitrary::{Arbitrary, Unstructured};
|
||||||
|
|
||||||
use self::error::{MissingDigitsKind, ParseAmountErrorInner, ParseErrorInner};
|
use self::error::{MissingDigitsKind, ParseAmountErrorInner, ParseErrorInner};
|
||||||
|
use crate::CheckedSum;
|
||||||
|
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
@ -593,13 +594,6 @@ enum DisplayStyle {
|
||||||
DynamicDenomination,
|
DynamicDenomination,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the sum over the iterator using checked arithmetic.
|
|
||||||
pub trait CheckedSum<R>: sealed::Sealed<R> {
|
|
||||||
/// Calculates the sum over the iterator using checked arithmetic. If an
|
|
||||||
/// overflow happens it returns [`None`].
|
|
||||||
fn checked_sum(self) -> Option<R>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> CheckedSum<Amount> for T
|
impl<T> CheckedSum<Amount> for T
|
||||||
where
|
where
|
||||||
T: Iterator<Item = Amount>,
|
T: Iterator<Item = Amount>,
|
||||||
|
@ -616,16 +610,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod sealed {
|
|
||||||
use super::{Amount, SignedAmount};
|
|
||||||
|
|
||||||
/// Used to seal the `CheckedSum` trait
|
|
||||||
pub trait Sealed<A> {}
|
|
||||||
|
|
||||||
impl<T> Sealed<Amount> for T where T: Iterator<Item = Amount> {}
|
|
||||||
impl<T> Sealed<SignedAmount> for T where T: Iterator<Item = SignedAmount> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "arbitrary")]
|
#[cfg(feature = "arbitrary")]
|
||||||
impl<'a> Arbitrary<'a> for Denomination {
|
impl<'a> Arbitrary<'a> for Denomination {
|
||||||
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||||
|
|
|
@ -69,3 +69,21 @@ pub(crate) use self::result::OptionExt;
|
||||||
#[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")]
|
#[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub type BlockInterval = BlockHeightInterval;
|
pub type BlockInterval = BlockHeightInterval;
|
||||||
|
|
||||||
|
/// Calculates the sum over the iterator using checked arithmetic.
|
||||||
|
pub trait CheckedSum<R>: sealed::Sealed<R> {
|
||||||
|
/// Calculates the sum over the iterator using checked arithmetic. If an
|
||||||
|
/// overflow happens it returns [`None`].
|
||||||
|
fn checked_sum(self) -> Option<R>;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod sealed {
|
||||||
|
use super::{Amount, SignedAmount, Weight};
|
||||||
|
|
||||||
|
/// Used to seal the `CheckedSum` trait
|
||||||
|
pub trait Sealed<A> {}
|
||||||
|
|
||||||
|
impl<T> Sealed<Amount> for T where T: Iterator<Item = Amount> {}
|
||||||
|
impl<T> Sealed<SignedAmount> for T where T: Iterator<Item = SignedAmount> {}
|
||||||
|
impl<T> Sealed<Weight> for T where T: Iterator<Item = Weight> {}
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ use arbitrary::{Arbitrary, Unstructured};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
use crate::CheckedSum;
|
||||||
|
|
||||||
/// The factor that non-witness serialization data is multiplied by during weight calculation.
|
/// The factor that non-witness serialization data is multiplied by during weight calculation.
|
||||||
pub const WITNESS_SCALE_FACTOR: usize = 4;
|
pub const WITNESS_SCALE_FACTOR: usize = 4;
|
||||||
|
|
||||||
|
@ -241,6 +243,13 @@ impl ops::RemAssign<u64> for Weight {
|
||||||
fn rem_assign(&mut self, rhs: u64) { *self = Weight::from_wu(self.to_wu() % rhs); }
|
fn rem_assign(&mut self, rhs: u64) { *self = Weight::from_wu(self.to_wu() % rhs); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> CheckedSum<Weight> for T
|
||||||
|
where
|
||||||
|
T: Iterator<Item = Weight>,
|
||||||
|
{
|
||||||
|
fn checked_sum(mut self) -> Option<Weight> { self.try_fold(Weight::ZERO, Weight::checked_add) }
|
||||||
|
}
|
||||||
|
|
||||||
impl core::iter::Sum for Weight {
|
impl core::iter::Sum for Weight {
|
||||||
fn sum<I>(iter: I) -> Self
|
fn sum<I>(iter: I) -> Self
|
||||||
where
|
where
|
||||||
|
@ -524,4 +533,16 @@ mod tests {
|
||||||
weight %= 3;
|
weight %= 3;
|
||||||
assert_eq!(weight, Weight::from_wu(1));
|
assert_eq!(weight, Weight::from_wu(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
fn checked_sum_weights() {
|
||||||
|
assert_eq!([].into_iter().checked_sum(), Some(Weight::ZERO));
|
||||||
|
|
||||||
|
let sum = alloc::vec![0, 1, 2].iter().map(|&w| Weight::from_wu(w)).checked_sum().unwrap();
|
||||||
|
assert_eq!(sum, Weight::from_wu(3));
|
||||||
|
|
||||||
|
let sum = alloc::vec![1, u64::MAX].iter().map(|&w| Weight::from_wu(w)).checked_sum();
|
||||||
|
assert!(sum.is_none());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use arbitrary::{Arbitrary, Unstructured};
|
||||||
use bitcoin_units::locktime::{absolute, relative}; // Typical usage is `absolute::Height`.
|
use bitcoin_units::locktime::{absolute, relative}; // Typical usage is `absolute::Height`.
|
||||||
use bitcoin_units::{
|
use bitcoin_units::{
|
||||||
amount, block, fee_rate, locktime, parse, weight, Amount, BlockHeight, BlockInterval, BlockMtp,
|
amount, block, fee_rate, locktime, parse, weight, Amount, BlockHeight, BlockInterval, BlockMtp,
|
||||||
BlockMtpInterval, BlockTime, FeeRate, SignedAmount, Weight,
|
BlockMtpInterval, BlockTime, CheckedSum, FeeRate, SignedAmount, Weight,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A struct that includes all public non-error enums.
|
/// A struct that includes all public non-error enums.
|
||||||
|
@ -272,7 +272,8 @@ fn regression_default() {
|
||||||
fn dyn_compatible() {
|
fn dyn_compatible() {
|
||||||
// If this builds then traits are dyn compatible.
|
// If this builds then traits are dyn compatible.
|
||||||
struct Traits {
|
struct Traits {
|
||||||
a: Box<dyn amount::CheckedSum<Amount>>,
|
a: Box<dyn CheckedSum<Amount>>,
|
||||||
|
b: Box<dyn CheckedSum<Weight>>,
|
||||||
// These traits are explicitly not dyn compatible.
|
// These traits are explicitly not dyn compatible.
|
||||||
// b: Box<dyn amount::serde::SerdeAmount>,
|
// b: Box<dyn amount::serde::SerdeAmount>,
|
||||||
// c: Box<dyn amount::serde::SerdeAmountForOpt>,
|
// c: Box<dyn amount::serde::SerdeAmountForOpt>,
|
||||||
|
|
Loading…
Reference in New Issue