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