1use core::num::NonZeroU64;
6use core::{fmt, ops};
7
8#[cfg(feature = "arbitrary")]
9use arbitrary::{Arbitrary, Unstructured};
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12
13use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
14use crate::{Amount, FeeRate, NumOpResult};
15
16pub const WITNESS_SCALE_FACTOR: usize = 4;
18
19mod encapsulate {
20 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
25 pub struct Weight(u64);
26
27 impl Weight {
28 #[inline]
30 pub const fn from_wu(wu: u64) -> Self { Self(wu) }
31
32 #[inline]
36 pub const fn to_wu(self) -> u64 { self.0 }
37 }
38}
39#[doc(inline)]
40pub use encapsulate::Weight;
41
42impl Weight {
43 pub const ZERO: Self = Self::from_wu(0);
47
48 pub const MIN: Self = Self::from_wu(u64::MIN);
52
53 pub const MAX: Self = Self::from_wu(u64::MAX);
55
56 pub const WITNESS_SCALE_FACTOR: u64 = WITNESS_SCALE_FACTOR as u64; pub const MAX_BLOCK: Self = Self::from_wu(4_000_000);
61
62 pub const MIN_TRANSACTION: Self = Self::from_wu(Self::WITNESS_SCALE_FACTOR * 60);
64
65 #[inline]
67 pub const fn from_kwu(wu: u64) -> Option<Self> {
68 match wu.checked_mul(1000) {
70 Some(wu) => Some(Self::from_wu(wu)),
71 None => None,
72 }
73 }
74
75 #[inline]
77 pub const fn from_vb(vb: u64) -> Option<Self> {
78 match vb.checked_mul(Self::WITNESS_SCALE_FACTOR) {
80 Some(wu) => Some(Self::from_wu(wu)),
81 None => None,
82 }
83 }
84
85 #[inline]
87 pub const fn from_vb_unchecked(vb: u64) -> Self {
88 Self::from_wu(vb * Self::WITNESS_SCALE_FACTOR)
89 }
90
91 #[inline]
100 pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
101 let weight = parse_int::hex_u64_prefixed(s)?;
102 Ok(Self::from_wu(weight))
103 }
104
105 #[inline]
114 pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
115 let weight = parse_int::hex_u64_unprefixed(s)?;
116 Ok(Self::from_wu(weight))
117 }
118
119 #[inline]
121 pub const fn to_kwu_floor(self) -> u64 { self.to_wu() / 1000 }
122
123 #[inline]
125 pub const fn to_kwu_ceil(self) -> u64 { self.to_wu().div_ceil(1_000) }
126
127 #[inline]
129 pub const fn to_vbytes_floor(self) -> u64 { self.to_wu() / Self::WITNESS_SCALE_FACTOR }
130
131 #[inline]
133 pub const fn to_vbytes_ceil(self) -> u64 { self.to_wu().div_ceil(Self::WITNESS_SCALE_FACTOR) }
134
135 #[inline]
139 #[must_use]
140 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
141 match self.to_wu().checked_add(rhs.to_wu()) {
143 Some(wu) => Some(Self::from_wu(wu)),
144 None => None,
145 }
146 }
147
148 #[inline]
152 #[must_use]
153 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
154 match self.to_wu().checked_sub(rhs.to_wu()) {
156 Some(wu) => Some(Self::from_wu(wu)),
157 None => None,
158 }
159 }
160
161 #[inline]
165 #[must_use]
166 pub const fn checked_mul(self, rhs: u64) -> Option<Self> {
167 match self.to_wu().checked_mul(rhs) {
169 Some(wu) => Some(Self::from_wu(wu)),
170 None => None,
171 }
172 }
173
174 #[inline]
178 #[must_use]
179 pub const fn checked_div(self, rhs: u64) -> Option<Self> {
180 match self.to_wu().checked_div(rhs) {
182 Some(wu) => Some(Self::from_wu(wu)),
183 None => None,
184 }
185 }
186
187 #[inline]
193 pub const fn mul_by_fee_rate(self, fee_rate: FeeRate) -> NumOpResult<Amount> {
194 fee_rate.mul_by_weight(self)
195 }
196}
197
198crate::internal_macros::impl_fmt_traits_for_u32_wrapper!(Weight, to_wu);
199
200impl fmt::Display for Weight {
202 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203 if f.alternate() {
204 write!(f, "{} wu", self.to_wu())
205 } else {
206 fmt::Display::fmt(&self.to_wu(), f)
207 }
208 }
209}
210
211impl From<Weight> for u64 {
212 #[inline]
213 fn from(value: Weight) -> Self { value.to_wu() }
214}
215
216crate::internal_macros::impl_op_for_references! {
217 impl ops::Add<Weight> for Weight {
218 type Output = Weight;
219
220 fn add(self, rhs: Weight) -> Self::Output { Weight::from_wu(self.to_wu() + rhs.to_wu()) }
221 }
222 impl ops::Sub<Weight> for Weight {
223 type Output = Weight;
224
225 fn sub(self, rhs: Weight) -> Self::Output { Weight::from_wu(self.to_wu() - rhs.to_wu()) }
226 }
227
228 impl ops::Mul<u64> for Weight {
229 type Output = Weight;
230
231 fn mul(self, rhs: u64) -> Self::Output { Weight::from_wu(self.to_wu() * rhs) }
232 }
233 impl ops::Mul<Weight> for u64 {
234 type Output = Weight;
235
236 fn mul(self, rhs: Weight) -> Self::Output { Weight::from_wu(self * rhs.to_wu()) }
237 }
238 impl ops::Div<u64> for Weight {
239 type Output = Weight;
240
241 fn div(self, rhs: u64) -> Self::Output { Weight::from_wu(self.to_wu() / rhs) }
242 }
243 impl ops::Div<Weight> for Weight {
244 type Output = u64;
245
246 fn div(self, rhs: Weight) -> Self::Output { self.to_wu() / rhs.to_wu() }
247 }
248 impl ops::Rem<u64> for Weight {
249 type Output = Weight;
250
251 fn rem(self, rhs: u64) -> Self::Output { Weight::from_wu(self.to_wu() % rhs) }
252 }
253 impl ops::Rem<Weight> for Weight {
254 type Output = u64;
255
256 fn rem(self, rhs: Weight) -> Self::Output { self.to_wu() % rhs.to_wu() }
257 }
258 impl ops::Div<NonZeroU64> for Weight {
259 type Output = Weight;
260
261 fn div(self, rhs: NonZeroU64) -> Self::Output{ Self::from_wu(self.to_wu() / rhs.get()) }
262 }
263}
264crate::internal_macros::impl_add_assign!(Weight);
265crate::internal_macros::impl_sub_assign!(Weight);
266
267impl ops::MulAssign<u64> for Weight {
268 #[inline]
269 fn mul_assign(&mut self, rhs: u64) { *self = Self::from_wu(self.to_wu() * rhs); }
270}
271
272impl ops::DivAssign<u64> for Weight {
273 #[inline]
274 fn div_assign(&mut self, rhs: u64) { *self = Self::from_wu(self.to_wu() / rhs); }
275}
276
277impl ops::RemAssign<u64> for Weight {
278 #[inline]
279 fn rem_assign(&mut self, rhs: u64) { *self = Self::from_wu(self.to_wu() % rhs); }
280}
281
282impl core::iter::Sum for Weight {
283 #[inline]
284 fn sum<I>(iter: I) -> Self
285 where
286 I: Iterator<Item = Self>,
287 {
288 Self::from_wu(iter.map(Self::to_wu).sum())
289 }
290}
291
292impl<'a> core::iter::Sum<&'a Self> for Weight {
293 #[inline]
294 fn sum<I>(iter: I) -> Self
295 where
296 I: Iterator<Item = &'a Self>,
297 {
298 iter.copied().sum()
299 }
300}
301
302parse_int::impl_parse_str_from_int_infallible!(Weight, u64, from_wu);
303
304#[cfg(feature = "serde")]
305impl Serialize for Weight {
306 #[inline]
307 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
308 where
309 S: Serializer,
310 {
311 u64::serialize(&self.to_wu(), s)
312 }
313}
314
315#[cfg(feature = "serde")]
316impl<'de> Deserialize<'de> for Weight {
317 #[inline]
318 fn deserialize<D>(d: D) -> Result<Self, D::Error>
319 where
320 D: Deserializer<'de>,
321 {
322 Ok(Self::from_wu(u64::deserialize(d)?))
323 }
324}
325
326#[cfg(feature = "arbitrary")]
327impl<'a> Arbitrary<'a> for Weight {
328 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
329 let w = u64::arbitrary(u)?;
330 Ok(Self::from_wu(w))
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 use core::num::NonZeroU64;
337
338 use super::*;
339
340 const ONE: Weight = Weight::from_wu(1);
341 const TWO: Weight = Weight::from_wu(2);
342 const FOUR: Weight = Weight::from_wu(4);
343
344 #[test]
345 fn sanity_check() {
346 assert_eq!(Weight::MIN_TRANSACTION, Weight::from_wu(240));
347 }
348
349 #[test]
350 #[allow(clippy::op_ref)]
351 fn weight_div_nonzero() {
352 let w = Weight::from_wu(100);
353 let divisor = NonZeroU64::new(4).unwrap();
354 assert_eq!(w / divisor, Weight::from_wu(25));
355 assert_eq!(&w / &divisor, Weight::from_wu(25));
357 assert_eq!(w / &divisor, Weight::from_wu(25));
358 }
359
360 #[test]
361 fn from_kwu() {
362 let got = Weight::from_kwu(1).unwrap();
363 let want = Weight::from_wu(1_000);
364 assert_eq!(got, want);
365 }
366
367 #[test]
368 fn from_kwu_overflows() { assert!(Weight::from_kwu(u64::MAX).is_none()) }
369
370 #[test]
371 fn from_vb() {
372 let got = Weight::from_vb(1).unwrap();
373 let want = Weight::from_wu(4);
374 assert_eq!(got, want);
375 }
376
377 #[test]
378 fn from_vb_overflows() {
379 assert!(Weight::from_vb(u64::MAX).is_none());
380 }
381
382 #[test]
383 fn from_vb_unchecked() {
384 let got = Weight::from_vb_unchecked(1);
385 let want = Weight::from_wu(4);
386 assert_eq!(got, want);
387 }
388
389 #[test]
390 #[cfg(debug_assertions)]
391 #[should_panic = "attempt to multiply with overflow"]
392 fn from_vb_unchecked_panic() { Weight::from_vb_unchecked(u64::MAX); }
393
394 #[test]
395 #[cfg(feature = "alloc")]
396 fn try_from_string() {
397 let weight_value: alloc::string::String = "10".into();
398 let got = Weight::try_from(weight_value).unwrap();
399 let want = Weight::from_wu(10);
400 assert_eq!(got, want);
401
402 let weight_value: alloc::string::String = "0xab".into();
404 assert!(Weight::try_from(weight_value).is_err());
405 let weight_value: alloc::string::String = "10.123".into();
406 assert!(Weight::try_from(weight_value).is_err());
407 }
408
409 #[test]
410 #[cfg(feature = "alloc")]
411 fn try_from_box() {
412 let weight_value: alloc::boxed::Box<str> = "10".into();
413 let got = Weight::try_from(weight_value).unwrap();
414 let want = Weight::from_wu(10);
415 assert_eq!(got, want);
416
417 let weight_value: alloc::boxed::Box<str> = "0xab".into();
419 assert!(Weight::try_from(weight_value).is_err());
420 let weight_value: alloc::boxed::Box<str> = "10.123".into();
421 assert!(Weight::try_from(weight_value).is_err());
422 }
423
424 #[test]
425 fn to_kwu_floor() {
426 assert_eq!(Weight::from_wu(5_000).to_kwu_floor(), 5);
427 assert_eq!(Weight::from_wu(5_999).to_kwu_floor(), 5);
428 }
429
430 #[test]
431 fn to_kwu_ceil() {
432 assert_eq!(Weight::from_wu(1_000).to_kwu_ceil(), 1);
433 assert_eq!(Weight::from_wu(1_001).to_kwu_ceil(), 2);
434 assert_eq!(Weight::MAX.to_kwu_ceil(), u64::MAX / 1_000 + 1);
435 }
436
437 #[test]
438 fn to_vb_floor() {
439 assert_eq!(Weight::from_wu(8).to_vbytes_floor(), 2);
440 assert_eq!(Weight::from_wu(9).to_vbytes_floor(), 2);
441 }
442
443 #[test]
444 fn to_vb_ceil() {
445 assert_eq!(Weight::from_wu(4).to_vbytes_ceil(), 1);
446 assert_eq!(Weight::from_wu(5).to_vbytes_ceil(), 2);
447 assert_eq!(Weight::MAX.to_vbytes_ceil(), u64::MAX / Weight::WITNESS_SCALE_FACTOR + 1);
448 }
449
450 #[test]
451 fn checked_add() {
452 assert_eq!(ONE.checked_add(ONE).unwrap(), TWO);
453 }
454
455 #[test]
456 fn checked_add_overflows() { assert!(Weight::MAX.checked_add(ONE).is_none()) }
457
458 #[test]
459 fn checked_sub() {
460 assert_eq!(TWO.checked_sub(ONE).unwrap(), ONE);
461 }
462
463 #[test]
464 fn checked_sub_overflows() { assert!(Weight::ZERO.checked_sub(ONE).is_none()) }
465
466 #[test]
467 fn checked_mul() {
468 assert_eq!(TWO.checked_mul(1).unwrap(), TWO);
469 assert_eq!(TWO.checked_mul(2).unwrap(), FOUR);
470 }
471
472 #[test]
473 fn checked_mul_overflows() { assert!(Weight::MAX.checked_mul(2).is_none()) }
474
475 #[test]
476 fn checked_div() {
477 assert_eq!(FOUR.checked_div(2).unwrap(), TWO);
478 assert_eq!(TWO.checked_div(1).unwrap(), TWO);
479 }
480
481 #[test]
482 fn checked_div_overflows() { assert!(TWO.checked_div(0).is_none()) }
483
484 #[test]
485 #[allow(clippy::op_ref)]
486 fn addition() {
487 let one = Weight::from_wu(1);
488 let two = Weight::from_wu(2);
489 let three = Weight::from_wu(3);
490
491 assert!(one + two == three);
492 assert!(&one + two == three);
493 assert!(one + &two == three);
494 assert!(&one + &two == three);
495 }
496
497 #[test]
498 #[allow(clippy::op_ref)]
499 fn subtract() {
500 let ten = Weight::from_wu(10);
501 let seven = Weight::from_wu(7);
502 let three = Weight::from_wu(3);
503
504 assert_eq!(ten - seven, three);
505 assert_eq!(&ten - seven, three);
506 assert_eq!(ten - &seven, three);
507 assert_eq!(&ten - &seven, three);
508 }
509
510 #[test]
511 #[allow(clippy::op_ref)]
512 fn multiply() {
513 let two = Weight::from_wu(2);
514 let six = Weight::from_wu(6);
515
516 assert_eq!(3_u64 * two, six);
517 assert_eq!(two * 3_u64, six);
518 }
519
520 #[test]
521 fn divide() {
522 let eight = Weight::from_wu(8);
523 let four = Weight::from_wu(4);
524
525 assert_eq!(eight / four, 2_u64);
526 assert_eq!(eight / 4_u64, Weight::from_wu(2));
527 }
528
529 #[test]
530 fn add_assign() {
531 let mut f = Weight::from_wu(1);
532 f += Weight::from_wu(2);
533 assert_eq!(f, Weight::from_wu(3));
534
535 let mut f = Weight::from_wu(1);
536 f += &Weight::from_wu(2);
537 assert_eq!(f, Weight::from_wu(3));
538 }
539
540 #[test]
541 fn sub_assign() {
542 let mut f = Weight::from_wu(3);
543 f -= Weight::from_wu(2);
544 assert_eq!(f, Weight::from_wu(1));
545
546 let mut f = Weight::from_wu(3);
547 f -= &Weight::from_wu(2);
548 assert_eq!(f, Weight::from_wu(1));
549 }
550
551 #[test]
552 fn mul_assign() {
553 let mut w = Weight::from_wu(3);
554 w *= 2_u64;
555 assert_eq!(w, Weight::from_wu(6));
556 }
557
558 #[test]
559 fn div_assign() {
560 let mut w = Weight::from_wu(8);
561 w /= Weight::from_wu(4).into();
562 assert_eq!(w, Weight::from_wu(2));
563 }
564
565 #[test]
566 fn remainder() {
567 let weight10 = Weight::from_wu(10);
568 let weight3 = Weight::from_wu(3);
569
570 let remainder = weight10 % weight3;
571 assert_eq!(remainder, 1);
572
573 let remainder = weight10 % 3;
574 assert_eq!(remainder, Weight::from_wu(1));
575 }
576
577 #[test]
578 fn remainder_assign() {
579 let mut weight = Weight::from_wu(10);
580 weight %= 3;
581 assert_eq!(weight, Weight::from_wu(1));
582 }
583
584 #[test]
585 fn iter_sum() {
586 let values = [
587 Weight::from_wu(10),
588 Weight::from_wu(50),
589 Weight::from_wu(30),
590 Weight::from_wu(5),
591 Weight::from_wu(5),
592 ];
593 let got: Weight = values.into_iter().sum();
594 let want = Weight::from_wu(100);
595 assert_eq!(got, want);
596 }
597
598 #[test]
599 fn iter_sum_ref() {
600 let values = [
601 Weight::from_wu(10),
602 Weight::from_wu(50),
603 Weight::from_wu(30),
604 Weight::from_wu(5),
605 Weight::from_wu(5),
606 ];
607 let got: Weight = values.iter().sum();
608 let want = Weight::from_wu(100);
609 assert_eq!(got, want);
610 }
611
612 #[test]
613 fn iter_sum_empty() {
614 let values: [Weight; 0] = [];
615 let got: Weight = values.into_iter().sum();
616 let want = Weight::from_wu(0);
617 assert_eq!(got, want);
618 }
619}