Skip to content

Commit 0064ad6

Browse files
committed
Merge rust-bitcoin#4557: Move CheckedSum and add Weight
9dac4d6 Implement CheckedSum for Weight iterator (yancy) 0dbcd09 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: ACK 9dac4d6 apoelstra: ACK 9dac4d6; successfully ran local tests Tree-SHA512: 3e4b7f79074e23493ccd17a026542081f0d7a811f4f35edb7994ada95bf414a166531f142ad4986d27fcec448209b2ffa56813b495b5df6b6e8fcd589392e0c1
2 parents 5e0b86d + 9dac4d6 commit 0064ad6

File tree

5 files changed

+47
-22
lines changed

5 files changed

+47
-22
lines changed

bitcoin/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,15 @@ pub mod amount {
204204

205205
#[rustfmt::skip] // Keep public re-exports separate.
206206
#[doc(inline)]
207+
pub use units::CheckedSum;
208+
#[cfg(feature = "serde")]
209+
pub use units::amount::serde;
207210
pub use units::amount::{
208-
Amount, CheckedSum, Denomination, Display, InvalidCharacterError, MissingDenominationError,
211+
Amount, Denomination, Display, InvalidCharacterError, MissingDenominationError,
209212
MissingDigitsError, OutOfRangeError, ParseAmountError, ParseDenominationError, ParseError,
210213
PossiblyConfusingDenominationError, SignedAmount, TooPreciseError,
211214
UnknownDenominationError,
212215
};
213-
#[cfg(feature = "serde")]
214-
pub use units::amount::serde;
215216

216217
impl Decodable for Amount {
217218
#[inline]

units/src/amount/mod.rs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use core::str::FromStr;
2626
use arbitrary::{Arbitrary, Unstructured};
2727

2828
use self::error::{MissingDigitsKind, ParseAmountErrorInner, ParseErrorInner};
29+
use crate::CheckedSum;
2930

3031
#[rustfmt::skip] // Keep public re-exports separate.
3132
#[doc(inline)]
@@ -593,13 +594,6 @@ enum DisplayStyle {
593594
DynamicDenomination,
594595
}
595596

596-
/// Calculates the sum over the iterator using checked arithmetic.
597-
pub trait CheckedSum<R>: sealed::Sealed<R> {
598-
/// Calculates the sum over the iterator using checked arithmetic. If an
599-
/// overflow happens it returns [`None`].
600-
fn checked_sum(self) -> Option<R>;
601-
}
602-
603597
impl<T> CheckedSum<Amount> for T
604598
where
605599
T: Iterator<Item = Amount>,
@@ -616,16 +610,6 @@ where
616610
}
617611
}
618612

619-
mod sealed {
620-
use super::{Amount, SignedAmount};
621-
622-
/// Used to seal the `CheckedSum` trait
623-
pub trait Sealed<A> {}
624-
625-
impl<T> Sealed<Amount> for T where T: Iterator<Item = Amount> {}
626-
impl<T> Sealed<SignedAmount> for T where T: Iterator<Item = SignedAmount> {}
627-
}
628-
629613
#[cfg(feature = "arbitrary")]
630614
impl<'a> Arbitrary<'a> for Denomination {
631615
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {

units/src/lib.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,21 @@ pub(crate) use self::result::OptionExt;
6969
#[deprecated(since = "TBD", note = "use `BlockHeightInterval` instead")]
7070
#[doc(hidden)]
7171
pub type BlockInterval = BlockHeightInterval;
72+
73+
/// Calculates the sum over the iterator using checked arithmetic.
74+
pub trait CheckedSum<R>: sealed::Sealed<R> {
75+
/// Calculates the sum over the iterator using checked arithmetic. If an
76+
/// overflow happens it returns [`None`].
77+
fn checked_sum(self) -> Option<R>;
78+
}
79+
80+
mod sealed {
81+
use super::{Amount, SignedAmount, Weight};
82+
83+
/// Used to seal the `CheckedSum` trait
84+
pub trait Sealed<A> {}
85+
86+
impl<T> Sealed<Amount> for T where T: Iterator<Item = Amount> {}
87+
impl<T> Sealed<SignedAmount> for T where T: Iterator<Item = SignedAmount> {}
88+
impl<T> Sealed<Weight> for T where T: Iterator<Item = Weight> {}
89+
}

units/src/weight.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use arbitrary::{Arbitrary, Unstructured};
1010
#[cfg(feature = "serde")]
1111
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1212

13+
use crate::CheckedSum;
14+
1315
/// The factor that non-witness serialization data is multiplied by during weight calculation.
1416
pub const WITNESS_SCALE_FACTOR: usize = 4;
1517

@@ -241,6 +243,13 @@ impl ops::RemAssign<u64> for Weight {
241243
fn rem_assign(&mut self, rhs: u64) { *self = Weight::from_wu(self.to_wu() % rhs); }
242244
}
243245

246+
impl<T> CheckedSum<Weight> for T
247+
where
248+
T: Iterator<Item = Weight>,
249+
{
250+
fn checked_sum(mut self) -> Option<Weight> { self.try_fold(Weight::ZERO, Weight::checked_add) }
251+
}
252+
244253
impl core::iter::Sum for Weight {
245254
fn sum<I>(iter: I) -> Self
246255
where
@@ -524,4 +533,16 @@ mod tests {
524533
weight %= 3;
525534
assert_eq!(weight, Weight::from_wu(1));
526535
}
536+
537+
#[test]
538+
#[cfg(feature = "alloc")]
539+
fn checked_sum_weights() {
540+
assert_eq!([].into_iter().checked_sum(), Some(Weight::ZERO));
541+
542+
let sum = alloc::vec![0, 1, 2].iter().map(|&w| Weight::from_wu(w)).checked_sum().unwrap();
543+
assert_eq!(sum, Weight::from_wu(3));
544+
545+
let sum = alloc::vec![1, u64::MAX].iter().map(|&w| Weight::from_wu(w)).checked_sum();
546+
assert!(sum.is_none());
547+
}
527548
}

units/tests/api.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use arbitrary::{Arbitrary, Unstructured};
1515
use bitcoin_units::locktime::{absolute, relative}; // Typical usage is `absolute::Height`.
1616
use bitcoin_units::{
1717
amount, block, fee_rate, locktime, parse, weight, Amount, BlockHeight, BlockInterval, BlockMtp,
18-
BlockMtpInterval, BlockTime, FeeRate, SignedAmount, Weight,
18+
BlockMtpInterval, BlockTime, CheckedSum, FeeRate, SignedAmount, Weight,
1919
};
2020

2121
/// A struct that includes all public non-error enums.
@@ -272,7 +272,8 @@ fn regression_default() {
272272
fn dyn_compatible() {
273273
// If this builds then traits are dyn compatible.
274274
struct Traits {
275-
a: Box<dyn amount::CheckedSum<Amount>>,
275+
a: Box<dyn CheckedSum<Amount>>,
276+
b: Box<dyn CheckedSum<Weight>>,
276277
// These traits are explicitly not dyn compatible.
277278
// b: Box<dyn amount::serde::SerdeAmount>,
278279
// c: Box<dyn amount::serde::SerdeAmountForOpt>,

0 commit comments

Comments
 (0)