1use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
19use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
20use sp_arithmetic::traits::{Bounded, CheckedAdd, CheckedSub, Zero};
21
22use super::*;
23
24#[derive(
25 Encode,
26 Decode,
27 DecodeWithMemTracking,
28 MaxEncodedLen,
29 TypeInfo,
30 Eq,
31 PartialEq,
32 Copy,
33 Clone,
34 Debug,
35 Default,
36)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
39pub struct Weight {
40 #[codec(compact)]
41 ref_time: u64,
43 #[codec(compact)]
44 proof_size: u64,
46}
47
48impl Weight {
49 pub const fn set_ref_time(mut self, c: u64) -> Self {
51 self.ref_time = c;
52 self
53 }
54
55 pub const fn set_proof_size(mut self, c: u64) -> Self {
57 self.proof_size = c;
58 self
59 }
60
61 pub const fn ref_time(&self) -> u64 {
63 self.ref_time
64 }
65
66 pub const fn proof_size(&self) -> u64 {
68 self.proof_size
69 }
70
71 pub fn ref_time_mut(&mut self) -> &mut u64 {
73 &mut self.ref_time
74 }
75
76 pub fn proof_size_mut(&mut self) -> &mut u64 {
78 &mut self.proof_size
79 }
80
81 pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX };
83
84 pub fn min(&self, other: Self) -> Self {
86 Self {
87 ref_time: self.ref_time.min(other.ref_time),
88 proof_size: self.proof_size.min(other.proof_size),
89 }
90 }
91
92 pub fn max(&self, other: Self) -> Self {
94 Self {
95 ref_time: self.ref_time.max(other.ref_time),
96 proof_size: self.proof_size.max(other.proof_size),
97 }
98 }
99
100 pub fn try_add(&self, other: &Self, limit: &Self) -> Option<Self> {
102 let total = self.checked_add(other)?;
103 if total.any_gt(*limit) {
104 None
105 } else {
106 Some(total)
107 }
108 }
109
110 pub const fn from_parts(ref_time: u64, proof_size: u64) -> Self {
112 Self { ref_time, proof_size }
113 }
114
115 pub const fn from_all(value: u64) -> Self {
117 Self { ref_time: value, proof_size: value }
118 }
119
120 #[must_use]
123 pub const fn saturating_add(self, rhs: Self) -> Self {
124 Self {
125 ref_time: self.ref_time.saturating_add(rhs.ref_time),
126 proof_size: self.proof_size.saturating_add(rhs.proof_size),
127 }
128 }
129
130 #[must_use]
133 pub const fn saturating_sub(self, rhs: Self) -> Self {
134 Self {
135 ref_time: self.ref_time.saturating_sub(rhs.ref_time),
136 proof_size: self.proof_size.saturating_sub(rhs.proof_size),
137 }
138 }
139
140 #[must_use]
143 pub const fn saturating_mul(self, scalar: u64) -> Self {
144 Self {
145 ref_time: self.ref_time.saturating_mul(scalar),
146 proof_size: self.proof_size.saturating_mul(scalar),
147 }
148 }
149
150 #[must_use]
153 pub const fn saturating_div(self, scalar: u64) -> Self {
154 Self {
155 ref_time: self.ref_time.saturating_div(scalar),
156 proof_size: self.proof_size.saturating_div(scalar),
157 }
158 }
159
160 #[must_use]
163 pub const fn saturating_pow(self, exp: u32) -> Self {
164 Self {
165 ref_time: self.ref_time.saturating_pow(exp),
166 proof_size: self.proof_size.saturating_pow(exp),
167 }
168 }
169
170 pub fn saturating_accrue(&mut self, amount: Self) {
172 *self = self.saturating_add(amount);
173 }
174
175 pub fn saturating_reduce(&mut self, amount: Self) {
177 *self = self.saturating_sub(amount);
178 }
179
180 #[must_use]
182 pub const fn checked_add(&self, rhs: &Self) -> Option<Self> {
183 let ref_time = match self.ref_time.checked_add(rhs.ref_time) {
184 Some(t) => t,
185 None => return None,
186 };
187 let proof_size = match self.proof_size.checked_add(rhs.proof_size) {
188 Some(s) => s,
189 None => return None,
190 };
191 Some(Self { ref_time, proof_size })
192 }
193
194 #[must_use]
197 pub const fn checked_sub(&self, rhs: &Self) -> Option<Self> {
198 let ref_time = match self.ref_time.checked_sub(rhs.ref_time) {
199 Some(t) => t,
200 None => return None,
201 };
202 let proof_size = match self.proof_size.checked_sub(rhs.proof_size) {
203 Some(s) => s,
204 None => return None,
205 };
206 Some(Self { ref_time, proof_size })
207 }
208
209 #[must_use]
212 pub const fn checked_mul(self, scalar: u64) -> Option<Self> {
213 let ref_time = match self.ref_time.checked_mul(scalar) {
214 Some(t) => t,
215 None => return None,
216 };
217 let proof_size = match self.proof_size.checked_mul(scalar) {
218 Some(s) => s,
219 None => return None,
220 };
221 Some(Self { ref_time, proof_size })
222 }
223
224 #[must_use]
227 pub const fn checked_div(self, scalar: u64) -> Option<Self> {
228 let ref_time = match self.ref_time.checked_div(scalar) {
229 Some(t) => t,
230 None => return None,
231 };
232 let proof_size = match self.proof_size.checked_div(scalar) {
233 Some(s) => s,
234 None => return None,
235 };
236 Some(Self { ref_time, proof_size })
237 }
238
239 #[must_use]
249 pub const fn checked_div_per_component(self, other: &Self) -> Option<u64> {
250 let mut all_zero = true;
251 let ref_time = match self.ref_time.checked_div(other.ref_time) {
252 Some(ref_time) => {
253 all_zero = false;
254 ref_time
255 },
256 None => u64::MAX,
257 };
258 let proof_size = match self.proof_size.checked_div(other.proof_size) {
259 Some(proof_size) => {
260 all_zero = false;
261 proof_size
262 },
263 None => u64::MAX,
264 };
265 if all_zero {
266 None
267 } else {
268 Some(if ref_time < proof_size { ref_time } else { proof_size })
269 }
270 }
271
272 pub fn checked_accrue(&mut self, amount: Self) -> Option<()> {
274 self.checked_add(&amount).map(|new_self| *self = new_self)
275 }
276
277 pub fn checked_reduce(&mut self, amount: Self) -> Option<()> {
279 self.checked_sub(&amount).map(|new_self| *self = new_self)
280 }
281
282 pub const fn zero() -> Self {
284 Self { ref_time: 0, proof_size: 0 }
285 }
286
287 #[must_use]
291 pub const fn add_ref_time(self, scalar: u64) -> Self {
292 Self { ref_time: self.ref_time + scalar, proof_size: self.proof_size }
293 }
294
295 #[must_use]
299 pub const fn add_proof_size(self, scalar: u64) -> Self {
300 Self { ref_time: self.ref_time, proof_size: self.proof_size + scalar }
301 }
302
303 #[must_use]
307 pub const fn sub_ref_time(self, scalar: u64) -> Self {
308 Self { ref_time: self.ref_time - scalar, proof_size: self.proof_size }
309 }
310
311 #[must_use]
315 pub const fn sub_proof_size(self, scalar: u64) -> Self {
316 Self { ref_time: self.ref_time, proof_size: self.proof_size - scalar }
317 }
318
319 #[must_use]
321 pub const fn saturating_add_ref_time(self, scalar: u64) -> Self {
322 Self { ref_time: self.ref_time.saturating_add(scalar), proof_size: self.proof_size }
323 }
324
325 #[must_use]
327 pub const fn saturating_add_proof_size(self, scalar: u64) -> Self {
328 Self { ref_time: self.ref_time, proof_size: self.proof_size.saturating_add(scalar) }
329 }
330
331 #[must_use]
333 pub const fn saturating_sub_ref_time(self, scalar: u64) -> Self {
334 Self { ref_time: self.ref_time.saturating_sub(scalar), proof_size: self.proof_size }
335 }
336
337 #[must_use]
339 pub const fn saturating_sub_proof_size(self, scalar: u64) -> Self {
340 Self { ref_time: self.ref_time, proof_size: self.proof_size.saturating_sub(scalar) }
341 }
342
343 #[must_use]
347 pub const fn div(self, scalar: u64) -> Self {
348 Self { ref_time: self.ref_time / scalar, proof_size: self.proof_size / scalar }
349 }
350
351 #[must_use]
355 pub const fn mul(self, scalar: u64) -> Self {
356 Self { ref_time: self.ref_time * scalar, proof_size: self.proof_size * scalar }
357 }
358
359 pub const fn any_gt(self, other: Self) -> bool {
362 self.ref_time > other.ref_time || self.proof_size > other.proof_size
363 }
364
365 pub const fn all_gt(self, other: Self) -> bool {
368 self.ref_time > other.ref_time && self.proof_size > other.proof_size
369 }
370
371 pub const fn any_lt(self, other: Self) -> bool {
374 self.ref_time < other.ref_time || self.proof_size < other.proof_size
375 }
376
377 pub const fn all_lt(self, other: Self) -> bool {
380 self.ref_time < other.ref_time && self.proof_size < other.proof_size
381 }
382
383 pub const fn any_gte(self, other: Self) -> bool {
386 self.ref_time >= other.ref_time || self.proof_size >= other.proof_size
387 }
388
389 pub const fn all_gte(self, other: Self) -> bool {
392 self.ref_time >= other.ref_time && self.proof_size >= other.proof_size
393 }
394
395 pub const fn any_lte(self, other: Self) -> bool {
398 self.ref_time <= other.ref_time || self.proof_size <= other.proof_size
399 }
400
401 pub const fn all_lte(self, other: Self) -> bool {
404 self.ref_time <= other.ref_time && self.proof_size <= other.proof_size
405 }
406
407 pub const fn any_eq(self, other: Self) -> bool {
410 self.ref_time == other.ref_time || self.proof_size == other.proof_size
411 }
412
413 }
415
416impl Zero for Weight {
417 fn zero() -> Self {
418 Self::zero()
419 }
420
421 fn is_zero(&self) -> bool {
422 self == &Self::zero()
423 }
424}
425
426impl Add for Weight {
427 type Output = Self;
428 fn add(self, rhs: Self) -> Self {
429 Self {
430 ref_time: self.ref_time + rhs.ref_time,
431 proof_size: self.proof_size + rhs.proof_size,
432 }
433 }
434}
435
436impl Sub for Weight {
437 type Output = Self;
438 fn sub(self, rhs: Self) -> Self {
439 Self {
440 ref_time: self.ref_time - rhs.ref_time,
441 proof_size: self.proof_size - rhs.proof_size,
442 }
443 }
444}
445
446impl<T> Mul<T> for Weight
447where
448 T: Mul<u64, Output = u64> + Copy,
449{
450 type Output = Self;
451 fn mul(self, b: T) -> Self {
452 Self { ref_time: b * self.ref_time, proof_size: b * self.proof_size }
453 }
454}
455
456#[cfg(any(test, feature = "std"))]
457impl From<u64> for Weight {
458 fn from(value: u64) -> Self {
459 Self::from_parts(value, value)
460 }
461}
462
463#[cfg(any(test, feature = "std"))]
464impl From<(u64, u64)> for Weight {
465 fn from(value: (u64, u64)) -> Self {
466 Self::from_parts(value.0, value.1)
467 }
468}
469
470macro_rules! weight_mul_per_impl {
471 ($($t:ty),* $(,)?) => {
472 $(
473 impl Mul<Weight> for $t {
474 type Output = Weight;
475 fn mul(self, b: Weight) -> Weight {
476 Weight {
477 ref_time: self * b.ref_time,
478 proof_size: self * b.proof_size,
479 }
480 }
481 }
482 )*
483 }
484}
485weight_mul_per_impl!(
486 sp_arithmetic::Percent,
487 sp_arithmetic::PerU16,
488 sp_arithmetic::Permill,
489 sp_arithmetic::Perbill,
490 sp_arithmetic::Perquintill,
491);
492
493macro_rules! weight_mul_primitive_impl {
494 ($($t:ty),* $(,)?) => {
495 $(
496 impl Mul<Weight> for $t {
497 type Output = Weight;
498 fn mul(self, b: Weight) -> Weight {
499 Weight {
500 ref_time: u64::from(self) * b.ref_time,
501 proof_size: u64::from(self) * b.proof_size,
502 }
503 }
504 }
505 )*
506 }
507}
508weight_mul_primitive_impl!(u8, u16, u32, u64);
509
510impl<T> Div<T> for Weight
511where
512 u64: Div<T, Output = u64>,
513 T: Copy,
514{
515 type Output = Self;
516 fn div(self, b: T) -> Self {
517 Self { ref_time: self.ref_time / b, proof_size: self.proof_size / b }
518 }
519}
520
521impl CheckedAdd for Weight {
522 fn checked_add(&self, rhs: &Self) -> Option<Self> {
523 self.checked_add(rhs)
524 }
525}
526
527impl CheckedSub for Weight {
528 fn checked_sub(&self, rhs: &Self) -> Option<Self> {
529 self.checked_sub(rhs)
530 }
531}
532
533impl core::fmt::Display for Weight {
534 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
535 write!(f, "Weight(ref_time: {}, proof_size: {})", self.ref_time, self.proof_size)
536 }
537}
538
539impl Bounded for Weight {
540 fn min_value() -> Self {
541 Zero::zero()
542 }
543 fn max_value() -> Self {
544 Self::MAX
545 }
546}
547
548impl AddAssign for Weight {
549 fn add_assign(&mut self, other: Self) {
550 *self = Self {
551 ref_time: self.ref_time + other.ref_time,
552 proof_size: self.proof_size + other.proof_size,
553 };
554 }
555}
556
557impl SubAssign for Weight {
558 fn sub_assign(&mut self, other: Self) {
559 *self = Self {
560 ref_time: self.ref_time - other.ref_time,
561 proof_size: self.proof_size - other.proof_size,
562 };
563 }
564}
565
566#[cfg(test)]
567mod tests {
568 use super::*;
569
570 #[test]
571 fn is_zero_works() {
572 assert!(Weight::zero().is_zero());
573 assert!(!Weight::from_parts(1, 0).is_zero());
574 assert!(!Weight::from_parts(0, 1).is_zero());
575 assert!(!Weight::MAX.is_zero());
576 }
577
578 #[test]
579 fn from_parts_works() {
580 assert_eq!(Weight::from_parts(0, 0), Weight { ref_time: 0, proof_size: 0 });
581 assert_eq!(Weight::from_parts(5, 5), Weight { ref_time: 5, proof_size: 5 });
582 assert_eq!(
583 Weight::from_parts(u64::MAX, u64::MAX),
584 Weight { ref_time: u64::MAX, proof_size: u64::MAX }
585 );
586 }
587
588 #[test]
589 fn from_all_works() {
590 assert_eq!(Weight::from_all(0), Weight::from_parts(0, 0));
591 assert_eq!(Weight::from_all(5), Weight::from_parts(5, 5));
592 assert_eq!(Weight::from_all(u64::MAX), Weight::from_parts(u64::MAX, u64::MAX));
593 }
594
595 #[test]
596 fn from_u64_works() {
597 assert_eq!(Weight::from_all(0), 0_u64.into());
598 assert_eq!(Weight::from_all(123), 123_u64.into());
599 assert_eq!(Weight::from_all(u64::MAX), u64::MAX.into());
600 }
601
602 #[test]
603 fn from_u64_pair_works() {
604 assert_eq!(Weight::from_parts(0, 1), (0, 1).into());
605 assert_eq!(Weight::from_parts(123, 321), (123u64, 321u64).into());
606 assert_eq!(Weight::from_parts(u64::MAX, 0), (u64::MAX, 0).into());
607 }
608
609 #[test]
610 fn saturating_reduce_works() {
611 let mut weight = Weight::from_parts(10, 20);
612 weight.saturating_reduce(Weight::from_all(5));
613 assert_eq!(weight, Weight::from_parts(5, 15));
614 weight.saturating_reduce(Weight::from_all(5));
615 assert_eq!(weight, Weight::from_parts(0, 10));
616 weight.saturating_reduce(Weight::from_all(11));
617 assert!(weight.is_zero());
618 weight.saturating_reduce(Weight::from_all(u64::MAX));
619 assert!(weight.is_zero());
620 }
621
622 #[test]
623 fn checked_accrue_works() {
624 let mut weight = Weight::from_parts(10, 20);
625 assert!(weight.checked_accrue(Weight::from_all(2)).is_some());
626 assert_eq!(weight, Weight::from_parts(12, 22));
627 assert!(weight.checked_accrue(Weight::from_parts(u64::MAX, 0)).is_none());
628 assert!(weight.checked_accrue(Weight::from_parts(0, u64::MAX)).is_none());
629 assert_eq!(weight, Weight::from_parts(12, 22));
630 assert!(weight
631 .checked_accrue(Weight::from_parts(u64::MAX - 12, u64::MAX - 22))
632 .is_some());
633 assert_eq!(weight, Weight::MAX);
634 assert!(weight.checked_accrue(Weight::from_parts(1, 0)).is_none());
635 assert!(weight.checked_accrue(Weight::from_parts(0, 1)).is_none());
636 assert_eq!(weight, Weight::MAX);
637 }
638
639 #[test]
640 fn checked_reduce_works() {
641 let mut weight = Weight::from_parts(10, 20);
642 assert!(weight.checked_reduce(Weight::from_all(2)).is_some());
643 assert_eq!(weight, Weight::from_parts(8, 18));
644 assert!(weight.checked_reduce(Weight::from_parts(9, 0)).is_none());
645 assert!(weight.checked_reduce(Weight::from_parts(0, 19)).is_none());
646 assert_eq!(weight, Weight::from_parts(8, 18));
647 assert!(weight.checked_reduce(Weight::from_parts(8, 0)).is_some());
648 assert_eq!(weight, Weight::from_parts(0, 18));
649 assert!(weight.checked_reduce(Weight::from_parts(0, 18)).is_some());
650 assert!(weight.is_zero());
651 }
652
653 #[test]
654 fn checked_div_per_component_works() {
655 assert_eq!(
656 Weight::from_parts(10, 20).checked_div_per_component(&Weight::from_parts(2, 10)),
657 Some(2)
658 );
659 assert_eq!(
660 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 10)),
661 Some(5)
662 );
663 assert_eq!(
664 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 10)),
665 Some(10)
666 );
667 assert_eq!(
668 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 1)),
669 Some(5)
670 );
671 assert_eq!(
672 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 10)),
673 Some(20)
674 );
675 assert_eq!(
676 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 0)),
677 Some(10)
678 );
679 assert_eq!(
680 Weight::from_parts(0, 200).checked_div_per_component(&Weight::from_parts(2, 3)),
681 Some(0)
682 );
683 assert_eq!(
684 Weight::from_parts(10, 0).checked_div_per_component(&Weight::from_parts(2, 3)),
685 Some(0)
686 );
687 assert_eq!(
688 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 0)),
689 None,
690 );
691 assert_eq!(
692 Weight::from_parts(0, 0).checked_div_per_component(&Weight::from_parts(0, 0)),
693 None,
694 );
695 }
696
697 #[test]
698 fn saturating_add_ref_time_works() {
699 let weight = Weight::from_parts(10, 20);
701 assert_eq!(weight.saturating_add_ref_time(5), Weight::from_parts(15, 20));
702
703 let weight = Weight::from_parts(u64::MAX - 5, 20);
705 assert_eq!(weight.saturating_add_ref_time(10), Weight::from_parts(u64::MAX, 20));
706
707 let weight = Weight::from_parts(u64::MAX, 20);
709 assert_eq!(weight.saturating_add_ref_time(1), Weight::from_parts(u64::MAX, 20));
710
711 let weight = Weight::from_parts(10, 20);
713 assert_eq!(weight.saturating_add_ref_time(0), Weight::from_parts(10, 20));
714
715 let weight = Weight::from_parts(10, 42);
717 assert_eq!(weight.saturating_add_ref_time(5).proof_size(), 42);
718 }
719
720 #[test]
721 fn saturating_add_proof_size_works() {
722 let weight = Weight::from_parts(10, 20);
724 assert_eq!(weight.saturating_add_proof_size(5), Weight::from_parts(10, 25));
725
726 let weight = Weight::from_parts(10, u64::MAX - 5);
728 assert_eq!(weight.saturating_add_proof_size(10), Weight::from_parts(10, u64::MAX));
729
730 let weight = Weight::from_parts(10, u64::MAX);
732 assert_eq!(weight.saturating_add_proof_size(1), Weight::from_parts(10, u64::MAX));
733
734 let weight = Weight::from_parts(10, 20);
736 assert_eq!(weight.saturating_add_proof_size(0), Weight::from_parts(10, 20));
737
738 let weight = Weight::from_parts(42, 20);
740 assert_eq!(weight.saturating_add_proof_size(5).ref_time(), 42);
741 }
742
743 #[test]
744 fn saturating_sub_ref_time_works() {
745 let weight = Weight::from_parts(10, 20);
747 assert_eq!(weight.saturating_sub_ref_time(5), Weight::from_parts(5, 20));
748
749 let weight = Weight::from_parts(5, 20);
751 assert_eq!(weight.saturating_sub_ref_time(10), Weight::from_parts(0, 20));
752
753 let weight = Weight::from_parts(0, 20);
755 assert_eq!(weight.saturating_sub_ref_time(1), Weight::from_parts(0, 20));
756
757 let weight = Weight::from_parts(10, 20);
759 assert_eq!(weight.saturating_sub_ref_time(0), Weight::from_parts(10, 20));
760
761 let weight = Weight::from_parts(10, 20);
763 assert_eq!(weight.saturating_sub_ref_time(10), Weight::from_parts(0, 20));
764
765 let weight = Weight::from_parts(10, 42);
767 assert_eq!(weight.saturating_sub_ref_time(5).proof_size(), 42);
768 }
769
770 #[test]
771 fn saturating_sub_proof_size_works() {
772 let weight = Weight::from_parts(10, 20);
774 assert_eq!(weight.saturating_sub_proof_size(5), Weight::from_parts(10, 15));
775
776 let weight = Weight::from_parts(10, 5);
778 assert_eq!(weight.saturating_sub_proof_size(10), Weight::from_parts(10, 0));
779
780 let weight = Weight::from_parts(10, 0);
782 assert_eq!(weight.saturating_sub_proof_size(1), Weight::from_parts(10, 0));
783
784 let weight = Weight::from_parts(10, 20);
786 assert_eq!(weight.saturating_sub_proof_size(0), Weight::from_parts(10, 20));
787
788 let weight = Weight::from_parts(10, 20);
790 assert_eq!(weight.saturating_sub_proof_size(20), Weight::from_parts(10, 0));
791
792 let weight = Weight::from_parts(42, 20);
794 assert_eq!(weight.saturating_sub_proof_size(5).ref_time(), 42);
795 }
796}