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 pub const fn saturating_add(self, rhs: Self) -> Self {
123 Self {
124 ref_time: self.ref_time.saturating_add(rhs.ref_time),
125 proof_size: self.proof_size.saturating_add(rhs.proof_size),
126 }
127 }
128
129 pub const fn saturating_sub(self, rhs: Self) -> Self {
132 Self {
133 ref_time: self.ref_time.saturating_sub(rhs.ref_time),
134 proof_size: self.proof_size.saturating_sub(rhs.proof_size),
135 }
136 }
137
138 pub const fn saturating_mul(self, scalar: u64) -> Self {
141 Self {
142 ref_time: self.ref_time.saturating_mul(scalar),
143 proof_size: self.proof_size.saturating_mul(scalar),
144 }
145 }
146
147 pub const fn saturating_div(self, scalar: u64) -> Self {
150 Self {
151 ref_time: self.ref_time.saturating_div(scalar),
152 proof_size: self.proof_size.saturating_div(scalar),
153 }
154 }
155
156 pub const fn saturating_pow(self, exp: u32) -> Self {
159 Self {
160 ref_time: self.ref_time.saturating_pow(exp),
161 proof_size: self.proof_size.saturating_pow(exp),
162 }
163 }
164
165 pub fn saturating_accrue(&mut self, amount: Self) {
167 *self = self.saturating_add(amount);
168 }
169
170 pub fn saturating_reduce(&mut self, amount: Self) {
172 *self = self.saturating_sub(amount);
173 }
174
175 pub const fn checked_add(&self, rhs: &Self) -> Option<Self> {
177 let ref_time = match self.ref_time.checked_add(rhs.ref_time) {
178 Some(t) => t,
179 None => return None,
180 };
181 let proof_size = match self.proof_size.checked_add(rhs.proof_size) {
182 Some(s) => s,
183 None => return None,
184 };
185 Some(Self { ref_time, proof_size })
186 }
187
188 pub const fn checked_sub(&self, rhs: &Self) -> Option<Self> {
191 let ref_time = match self.ref_time.checked_sub(rhs.ref_time) {
192 Some(t) => t,
193 None => return None,
194 };
195 let proof_size = match self.proof_size.checked_sub(rhs.proof_size) {
196 Some(s) => s,
197 None => return None,
198 };
199 Some(Self { ref_time, proof_size })
200 }
201
202 pub const fn checked_mul(self, scalar: u64) -> Option<Self> {
205 let ref_time = match self.ref_time.checked_mul(scalar) {
206 Some(t) => t,
207 None => return None,
208 };
209 let proof_size = match self.proof_size.checked_mul(scalar) {
210 Some(s) => s,
211 None => return None,
212 };
213 Some(Self { ref_time, proof_size })
214 }
215
216 pub const fn checked_div(self, scalar: u64) -> Option<Self> {
219 let ref_time = match self.ref_time.checked_div(scalar) {
220 Some(t) => t,
221 None => return None,
222 };
223 let proof_size = match self.proof_size.checked_div(scalar) {
224 Some(s) => s,
225 None => return None,
226 };
227 Some(Self { ref_time, proof_size })
228 }
229
230 pub const fn checked_div_per_component(self, other: &Self) -> Option<u64> {
240 let mut all_zero = true;
241 let ref_time = match self.ref_time.checked_div(other.ref_time) {
242 Some(ref_time) => {
243 all_zero = false;
244 ref_time
245 },
246 None => u64::MAX,
247 };
248 let proof_size = match self.proof_size.checked_div(other.proof_size) {
249 Some(proof_size) => {
250 all_zero = false;
251 proof_size
252 },
253 None => u64::MAX,
254 };
255 if all_zero {
256 None
257 } else {
258 Some(if ref_time < proof_size { ref_time } else { proof_size })
259 }
260 }
261
262 pub fn checked_accrue(&mut self, amount: Self) -> Option<()> {
264 self.checked_add(&amount).map(|new_self| *self = new_self)
265 }
266
267 pub fn checked_reduce(&mut self, amount: Self) -> Option<()> {
269 self.checked_sub(&amount).map(|new_self| *self = new_self)
270 }
271
272 pub const fn zero() -> Self {
274 Self { ref_time: 0, proof_size: 0 }
275 }
276
277 pub const fn add_ref_time(self, scalar: u64) -> Self {
281 Self { ref_time: self.ref_time + scalar, proof_size: self.proof_size }
282 }
283
284 pub const fn add_proof_size(self, scalar: u64) -> Self {
288 Self { ref_time: self.ref_time, proof_size: self.proof_size + scalar }
289 }
290
291 pub const fn sub_ref_time(self, scalar: u64) -> Self {
295 Self { ref_time: self.ref_time - scalar, proof_size: self.proof_size }
296 }
297
298 pub const fn sub_proof_size(self, scalar: u64) -> Self {
302 Self { ref_time: self.ref_time, proof_size: self.proof_size - scalar }
303 }
304
305 pub const fn saturating_add_ref_time(self, scalar: u64) -> Self {
307 Self { ref_time: self.ref_time.saturating_add(scalar), proof_size: self.proof_size }
308 }
309
310 pub const fn saturating_add_proof_size(self, scalar: u64) -> Self {
312 Self { ref_time: self.ref_time, proof_size: self.proof_size.saturating_add(scalar) }
313 }
314
315 pub const fn saturating_sub_ref_time(self, scalar: u64) -> Self {
317 Self { ref_time: self.ref_time.saturating_sub(scalar), proof_size: self.proof_size }
318 }
319
320 pub const fn saturating_sub_proof_size(self, scalar: u64) -> Self {
322 Self { ref_time: self.ref_time, proof_size: self.proof_size.saturating_sub(scalar) }
323 }
324
325 pub const fn div(self, scalar: u64) -> Self {
329 Self { ref_time: self.ref_time / scalar, proof_size: self.proof_size / scalar }
330 }
331
332 pub const fn mul(self, scalar: u64) -> Self {
336 Self { ref_time: self.ref_time * scalar, proof_size: self.proof_size * scalar }
337 }
338
339 pub const fn any_gt(self, other: Self) -> bool {
342 self.ref_time > other.ref_time || self.proof_size > other.proof_size
343 }
344
345 pub const fn all_gt(self, other: Self) -> bool {
348 self.ref_time > other.ref_time && self.proof_size > other.proof_size
349 }
350
351 pub const fn any_lt(self, other: Self) -> bool {
354 self.ref_time < other.ref_time || self.proof_size < other.proof_size
355 }
356
357 pub const fn all_lt(self, other: Self) -> bool {
360 self.ref_time < other.ref_time && self.proof_size < other.proof_size
361 }
362
363 pub const fn any_gte(self, other: Self) -> bool {
366 self.ref_time >= other.ref_time || self.proof_size >= other.proof_size
367 }
368
369 pub const fn all_gte(self, other: Self) -> bool {
372 self.ref_time >= other.ref_time && self.proof_size >= other.proof_size
373 }
374
375 pub const fn any_lte(self, other: Self) -> bool {
378 self.ref_time <= other.ref_time || self.proof_size <= other.proof_size
379 }
380
381 pub const fn all_lte(self, other: Self) -> bool {
384 self.ref_time <= other.ref_time && self.proof_size <= other.proof_size
385 }
386
387 pub const fn any_eq(self, other: Self) -> bool {
390 self.ref_time == other.ref_time || self.proof_size == other.proof_size
391 }
392
393 }
395
396impl Zero for Weight {
397 fn zero() -> Self {
398 Self::zero()
399 }
400
401 fn is_zero(&self) -> bool {
402 self == &Self::zero()
403 }
404}
405
406impl Add for Weight {
407 type Output = Self;
408 fn add(self, rhs: Self) -> Self {
409 Self {
410 ref_time: self.ref_time + rhs.ref_time,
411 proof_size: self.proof_size + rhs.proof_size,
412 }
413 }
414}
415
416impl Sub for Weight {
417 type Output = Self;
418 fn sub(self, rhs: Self) -> Self {
419 Self {
420 ref_time: self.ref_time - rhs.ref_time,
421 proof_size: self.proof_size - rhs.proof_size,
422 }
423 }
424}
425
426impl<T> Mul<T> for Weight
427where
428 T: Mul<u64, Output = u64> + Copy,
429{
430 type Output = Self;
431 fn mul(self, b: T) -> Self {
432 Self { ref_time: b * self.ref_time, proof_size: b * self.proof_size }
433 }
434}
435
436#[cfg(any(test, feature = "std"))]
437impl From<u64> for Weight {
438 fn from(value: u64) -> Self {
439 Self::from_parts(value, value)
440 }
441}
442
443#[cfg(any(test, feature = "std"))]
444impl From<(u64, u64)> for Weight {
445 fn from(value: (u64, u64)) -> Self {
446 Self::from_parts(value.0, value.1)
447 }
448}
449
450macro_rules! weight_mul_per_impl {
451 ($($t:ty),* $(,)?) => {
452 $(
453 impl Mul<Weight> for $t {
454 type Output = Weight;
455 fn mul(self, b: Weight) -> Weight {
456 Weight {
457 ref_time: self * b.ref_time,
458 proof_size: self * b.proof_size,
459 }
460 }
461 }
462 )*
463 }
464}
465weight_mul_per_impl!(
466 sp_arithmetic::Percent,
467 sp_arithmetic::PerU16,
468 sp_arithmetic::Permill,
469 sp_arithmetic::Perbill,
470 sp_arithmetic::Perquintill,
471);
472
473macro_rules! weight_mul_primitive_impl {
474 ($($t:ty),* $(,)?) => {
475 $(
476 impl Mul<Weight> for $t {
477 type Output = Weight;
478 fn mul(self, b: Weight) -> Weight {
479 Weight {
480 ref_time: u64::from(self) * b.ref_time,
481 proof_size: u64::from(self) * b.proof_size,
482 }
483 }
484 }
485 )*
486 }
487}
488weight_mul_primitive_impl!(u8, u16, u32, u64);
489
490impl<T> Div<T> for Weight
491where
492 u64: Div<T, Output = u64>,
493 T: Copy,
494{
495 type Output = Self;
496 fn div(self, b: T) -> Self {
497 Self { ref_time: self.ref_time / b, proof_size: self.proof_size / b }
498 }
499}
500
501impl CheckedAdd for Weight {
502 fn checked_add(&self, rhs: &Self) -> Option<Self> {
503 self.checked_add(rhs)
504 }
505}
506
507impl CheckedSub for Weight {
508 fn checked_sub(&self, rhs: &Self) -> Option<Self> {
509 self.checked_sub(rhs)
510 }
511}
512
513impl core::fmt::Display for Weight {
514 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
515 write!(f, "Weight(ref_time: {}, proof_size: {})", self.ref_time, self.proof_size)
516 }
517}
518
519impl Bounded for Weight {
520 fn min_value() -> Self {
521 Zero::zero()
522 }
523 fn max_value() -> Self {
524 Self::MAX
525 }
526}
527
528impl AddAssign for Weight {
529 fn add_assign(&mut self, other: Self) {
530 *self = Self {
531 ref_time: self.ref_time + other.ref_time,
532 proof_size: self.proof_size + other.proof_size,
533 };
534 }
535}
536
537impl SubAssign for Weight {
538 fn sub_assign(&mut self, other: Self) {
539 *self = Self {
540 ref_time: self.ref_time - other.ref_time,
541 proof_size: self.proof_size - other.proof_size,
542 };
543 }
544}
545
546#[cfg(test)]
547mod tests {
548 use super::*;
549
550 #[test]
551 fn is_zero_works() {
552 assert!(Weight::zero().is_zero());
553 assert!(!Weight::from_parts(1, 0).is_zero());
554 assert!(!Weight::from_parts(0, 1).is_zero());
555 assert!(!Weight::MAX.is_zero());
556 }
557
558 #[test]
559 fn from_parts_works() {
560 assert_eq!(Weight::from_parts(0, 0), Weight { ref_time: 0, proof_size: 0 });
561 assert_eq!(Weight::from_parts(5, 5), Weight { ref_time: 5, proof_size: 5 });
562 assert_eq!(
563 Weight::from_parts(u64::MAX, u64::MAX),
564 Weight { ref_time: u64::MAX, proof_size: u64::MAX }
565 );
566 }
567
568 #[test]
569 fn from_all_works() {
570 assert_eq!(Weight::from_all(0), Weight::from_parts(0, 0));
571 assert_eq!(Weight::from_all(5), Weight::from_parts(5, 5));
572 assert_eq!(Weight::from_all(u64::MAX), Weight::from_parts(u64::MAX, u64::MAX));
573 }
574
575 #[test]
576 fn from_u64_works() {
577 assert_eq!(Weight::from_all(0), 0_u64.into());
578 assert_eq!(Weight::from_all(123), 123_u64.into());
579 assert_eq!(Weight::from_all(u64::MAX), u64::MAX.into());
580 }
581
582 #[test]
583 fn from_u64_pair_works() {
584 assert_eq!(Weight::from_parts(0, 1), (0, 1).into());
585 assert_eq!(Weight::from_parts(123, 321), (123u64, 321u64).into());
586 assert_eq!(Weight::from_parts(u64::MAX, 0), (u64::MAX, 0).into());
587 }
588
589 #[test]
590 fn saturating_reduce_works() {
591 let mut weight = Weight::from_parts(10, 20);
592 weight.saturating_reduce(Weight::from_all(5));
593 assert_eq!(weight, Weight::from_parts(5, 15));
594 weight.saturating_reduce(Weight::from_all(5));
595 assert_eq!(weight, Weight::from_parts(0, 10));
596 weight.saturating_reduce(Weight::from_all(11));
597 assert!(weight.is_zero());
598 weight.saturating_reduce(Weight::from_all(u64::MAX));
599 assert!(weight.is_zero());
600 }
601
602 #[test]
603 fn checked_accrue_works() {
604 let mut weight = Weight::from_parts(10, 20);
605 assert!(weight.checked_accrue(Weight::from_all(2)).is_some());
606 assert_eq!(weight, Weight::from_parts(12, 22));
607 assert!(weight.checked_accrue(Weight::from_parts(u64::MAX, 0)).is_none());
608 assert!(weight.checked_accrue(Weight::from_parts(0, u64::MAX)).is_none());
609 assert_eq!(weight, Weight::from_parts(12, 22));
610 assert!(weight
611 .checked_accrue(Weight::from_parts(u64::MAX - 12, u64::MAX - 22))
612 .is_some());
613 assert_eq!(weight, Weight::MAX);
614 assert!(weight.checked_accrue(Weight::from_parts(1, 0)).is_none());
615 assert!(weight.checked_accrue(Weight::from_parts(0, 1)).is_none());
616 assert_eq!(weight, Weight::MAX);
617 }
618
619 #[test]
620 fn checked_reduce_works() {
621 let mut weight = Weight::from_parts(10, 20);
622 assert!(weight.checked_reduce(Weight::from_all(2)).is_some());
623 assert_eq!(weight, Weight::from_parts(8, 18));
624 assert!(weight.checked_reduce(Weight::from_parts(9, 0)).is_none());
625 assert!(weight.checked_reduce(Weight::from_parts(0, 19)).is_none());
626 assert_eq!(weight, Weight::from_parts(8, 18));
627 assert!(weight.checked_reduce(Weight::from_parts(8, 0)).is_some());
628 assert_eq!(weight, Weight::from_parts(0, 18));
629 assert!(weight.checked_reduce(Weight::from_parts(0, 18)).is_some());
630 assert!(weight.is_zero());
631 }
632
633 #[test]
634 fn checked_div_per_component_works() {
635 assert_eq!(
636 Weight::from_parts(10, 20).checked_div_per_component(&Weight::from_parts(2, 10)),
637 Some(2)
638 );
639 assert_eq!(
640 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 10)),
641 Some(5)
642 );
643 assert_eq!(
644 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 10)),
645 Some(10)
646 );
647 assert_eq!(
648 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 1)),
649 Some(5)
650 );
651 assert_eq!(
652 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 10)),
653 Some(20)
654 );
655 assert_eq!(
656 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 0)),
657 Some(10)
658 );
659 assert_eq!(
660 Weight::from_parts(0, 200).checked_div_per_component(&Weight::from_parts(2, 3)),
661 Some(0)
662 );
663 assert_eq!(
664 Weight::from_parts(10, 0).checked_div_per_component(&Weight::from_parts(2, 3)),
665 Some(0)
666 );
667 assert_eq!(
668 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 0)),
669 None,
670 );
671 assert_eq!(
672 Weight::from_parts(0, 0).checked_div_per_component(&Weight::from_parts(0, 0)),
673 None,
674 );
675 }
676
677 #[test]
678 fn saturating_add_ref_time_works() {
679 let weight = Weight::from_parts(10, 20);
681 assert_eq!(weight.saturating_add_ref_time(5), Weight::from_parts(15, 20));
682
683 let weight = Weight::from_parts(u64::MAX - 5, 20);
685 assert_eq!(weight.saturating_add_ref_time(10), Weight::from_parts(u64::MAX, 20));
686
687 let weight = Weight::from_parts(u64::MAX, 20);
689 assert_eq!(weight.saturating_add_ref_time(1), Weight::from_parts(u64::MAX, 20));
690
691 let weight = Weight::from_parts(10, 20);
693 assert_eq!(weight.saturating_add_ref_time(0), Weight::from_parts(10, 20));
694
695 let weight = Weight::from_parts(10, 42);
697 assert_eq!(weight.saturating_add_ref_time(5).proof_size(), 42);
698 }
699
700 #[test]
701 fn saturating_add_proof_size_works() {
702 let weight = Weight::from_parts(10, 20);
704 assert_eq!(weight.saturating_add_proof_size(5), Weight::from_parts(10, 25));
705
706 let weight = Weight::from_parts(10, u64::MAX - 5);
708 assert_eq!(weight.saturating_add_proof_size(10), Weight::from_parts(10, u64::MAX));
709
710 let weight = Weight::from_parts(10, u64::MAX);
712 assert_eq!(weight.saturating_add_proof_size(1), Weight::from_parts(10, u64::MAX));
713
714 let weight = Weight::from_parts(10, 20);
716 assert_eq!(weight.saturating_add_proof_size(0), Weight::from_parts(10, 20));
717
718 let weight = Weight::from_parts(42, 20);
720 assert_eq!(weight.saturating_add_proof_size(5).ref_time(), 42);
721 }
722
723 #[test]
724 fn saturating_sub_ref_time_works() {
725 let weight = Weight::from_parts(10, 20);
727 assert_eq!(weight.saturating_sub_ref_time(5), Weight::from_parts(5, 20));
728
729 let weight = Weight::from_parts(5, 20);
731 assert_eq!(weight.saturating_sub_ref_time(10), Weight::from_parts(0, 20));
732
733 let weight = Weight::from_parts(0, 20);
735 assert_eq!(weight.saturating_sub_ref_time(1), Weight::from_parts(0, 20));
736
737 let weight = Weight::from_parts(10, 20);
739 assert_eq!(weight.saturating_sub_ref_time(0), Weight::from_parts(10, 20));
740
741 let weight = Weight::from_parts(10, 20);
743 assert_eq!(weight.saturating_sub_ref_time(10), Weight::from_parts(0, 20));
744
745 let weight = Weight::from_parts(10, 42);
747 assert_eq!(weight.saturating_sub_ref_time(5).proof_size(), 42);
748 }
749
750 #[test]
751 fn saturating_sub_proof_size_works() {
752 let weight = Weight::from_parts(10, 20);
754 assert_eq!(weight.saturating_sub_proof_size(5), Weight::from_parts(10, 15));
755
756 let weight = Weight::from_parts(10, 5);
758 assert_eq!(weight.saturating_sub_proof_size(10), Weight::from_parts(10, 0));
759
760 let weight = Weight::from_parts(10, 0);
762 assert_eq!(weight.saturating_sub_proof_size(1), Weight::from_parts(10, 0));
763
764 let weight = Weight::from_parts(10, 20);
766 assert_eq!(weight.saturating_sub_proof_size(0), Weight::from_parts(10, 20));
767
768 let weight = Weight::from_parts(10, 20);
770 assert_eq!(weight.saturating_sub_proof_size(20), Weight::from_parts(10, 0));
771
772 let weight = Weight::from_parts(42, 20);
774 assert_eq!(weight.saturating_sub_proof_size(5).ref_time(), 42);
775 }
776}