1use codec::{Decode, 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(Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, Copy, Clone, Debug, Default)]
25#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
27pub struct Weight {
28 #[codec(compact)]
29 ref_time: u64,
31 #[codec(compact)]
32 proof_size: u64,
34}
35
36impl Weight {
37 pub const fn set_ref_time(mut self, c: u64) -> Self {
39 self.ref_time = c;
40 self
41 }
42
43 pub const fn set_proof_size(mut self, c: u64) -> Self {
45 self.proof_size = c;
46 self
47 }
48
49 pub const fn ref_time(&self) -> u64 {
51 self.ref_time
52 }
53
54 pub const fn proof_size(&self) -> u64 {
56 self.proof_size
57 }
58
59 pub fn ref_time_mut(&mut self) -> &mut u64 {
61 &mut self.ref_time
62 }
63
64 pub fn proof_size_mut(&mut self) -> &mut u64 {
66 &mut self.proof_size
67 }
68
69 pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX };
71
72 pub fn min(&self, other: Self) -> Self {
74 Self {
75 ref_time: self.ref_time.min(other.ref_time),
76 proof_size: self.proof_size.min(other.proof_size),
77 }
78 }
79
80 pub fn max(&self, other: Self) -> Self {
82 Self {
83 ref_time: self.ref_time.max(other.ref_time),
84 proof_size: self.proof_size.max(other.proof_size),
85 }
86 }
87
88 pub fn try_add(&self, other: &Self, limit: &Self) -> Option<Self> {
90 let total = self.checked_add(other)?;
91 if total.any_gt(*limit) {
92 None
93 } else {
94 Some(total)
95 }
96 }
97
98 pub const fn from_parts(ref_time: u64, proof_size: u64) -> Self {
100 Self { ref_time, proof_size }
101 }
102
103 pub const fn from_all(value: u64) -> Self {
105 Self { ref_time: value, proof_size: value }
106 }
107
108 pub const fn saturating_add(self, rhs: Self) -> Self {
111 Self {
112 ref_time: self.ref_time.saturating_add(rhs.ref_time),
113 proof_size: self.proof_size.saturating_add(rhs.proof_size),
114 }
115 }
116
117 pub const fn saturating_sub(self, rhs: Self) -> Self {
120 Self {
121 ref_time: self.ref_time.saturating_sub(rhs.ref_time),
122 proof_size: self.proof_size.saturating_sub(rhs.proof_size),
123 }
124 }
125
126 pub const fn saturating_mul(self, scalar: u64) -> Self {
129 Self {
130 ref_time: self.ref_time.saturating_mul(scalar),
131 proof_size: self.proof_size.saturating_mul(scalar),
132 }
133 }
134
135 pub const fn saturating_div(self, scalar: u64) -> Self {
138 Self {
139 ref_time: self.ref_time.saturating_div(scalar),
140 proof_size: self.proof_size.saturating_div(scalar),
141 }
142 }
143
144 pub const fn saturating_pow(self, exp: u32) -> Self {
147 Self {
148 ref_time: self.ref_time.saturating_pow(exp),
149 proof_size: self.proof_size.saturating_pow(exp),
150 }
151 }
152
153 pub fn saturating_accrue(&mut self, amount: Self) {
155 *self = self.saturating_add(amount);
156 }
157
158 pub fn saturating_reduce(&mut self, amount: Self) {
160 *self = self.saturating_sub(amount);
161 }
162
163 pub const fn checked_add(&self, rhs: &Self) -> Option<Self> {
165 let ref_time = match self.ref_time.checked_add(rhs.ref_time) {
166 Some(t) => t,
167 None => return None,
168 };
169 let proof_size = match self.proof_size.checked_add(rhs.proof_size) {
170 Some(s) => s,
171 None => return None,
172 };
173 Some(Self { ref_time, proof_size })
174 }
175
176 pub const fn checked_sub(&self, rhs: &Self) -> Option<Self> {
179 let ref_time = match self.ref_time.checked_sub(rhs.ref_time) {
180 Some(t) => t,
181 None => return None,
182 };
183 let proof_size = match self.proof_size.checked_sub(rhs.proof_size) {
184 Some(s) => s,
185 None => return None,
186 };
187 Some(Self { ref_time, proof_size })
188 }
189
190 pub const fn checked_mul(self, scalar: u64) -> Option<Self> {
193 let ref_time = match self.ref_time.checked_mul(scalar) {
194 Some(t) => t,
195 None => return None,
196 };
197 let proof_size = match self.proof_size.checked_mul(scalar) {
198 Some(s) => s,
199 None => return None,
200 };
201 Some(Self { ref_time, proof_size })
202 }
203
204 pub const fn checked_div(self, scalar: u64) -> Option<Self> {
207 let ref_time = match self.ref_time.checked_div(scalar) {
208 Some(t) => t,
209 None => return None,
210 };
211 let proof_size = match self.proof_size.checked_div(scalar) {
212 Some(s) => s,
213 None => return None,
214 };
215 Some(Self { ref_time, proof_size })
216 }
217
218 pub const fn checked_div_per_component(self, other: &Self) -> Option<u64> {
228 let mut all_zero = true;
229 let ref_time = match self.ref_time.checked_div(other.ref_time) {
230 Some(ref_time) => {
231 all_zero = false;
232 ref_time
233 },
234 None => u64::MAX,
235 };
236 let proof_size = match self.proof_size.checked_div(other.proof_size) {
237 Some(proof_size) => {
238 all_zero = false;
239 proof_size
240 },
241 None => u64::MAX,
242 };
243 if all_zero {
244 None
245 } else {
246 Some(if ref_time < proof_size { ref_time } else { proof_size })
247 }
248 }
249
250 pub fn checked_accrue(&mut self, amount: Self) -> Option<()> {
252 self.checked_add(&amount).map(|new_self| *self = new_self)
253 }
254
255 pub fn checked_reduce(&mut self, amount: Self) -> Option<()> {
257 self.checked_sub(&amount).map(|new_self| *self = new_self)
258 }
259
260 pub const fn zero() -> Self {
262 Self { ref_time: 0, proof_size: 0 }
263 }
264
265 pub const fn add_ref_time(self, scalar: u64) -> Self {
269 Self { ref_time: self.ref_time + scalar, proof_size: self.proof_size }
270 }
271
272 pub const fn add_proof_size(self, scalar: u64) -> Self {
276 Self { ref_time: self.ref_time, proof_size: self.proof_size + scalar }
277 }
278
279 pub const fn sub_ref_time(self, scalar: u64) -> Self {
283 Self { ref_time: self.ref_time - scalar, proof_size: self.proof_size }
284 }
285
286 pub const fn sub_proof_size(self, scalar: u64) -> Self {
290 Self { ref_time: self.ref_time, proof_size: self.proof_size - scalar }
291 }
292
293 pub const fn div(self, scalar: u64) -> Self {
297 Self { ref_time: self.ref_time / scalar, proof_size: self.proof_size / scalar }
298 }
299
300 pub const fn mul(self, scalar: u64) -> Self {
304 Self { ref_time: self.ref_time * scalar, proof_size: self.proof_size * scalar }
305 }
306
307 pub const fn any_gt(self, other: Self) -> bool {
310 self.ref_time > other.ref_time || self.proof_size > other.proof_size
311 }
312
313 pub const fn all_gt(self, other: Self) -> bool {
316 self.ref_time > other.ref_time && self.proof_size > other.proof_size
317 }
318
319 pub const fn any_lt(self, other: Self) -> bool {
322 self.ref_time < other.ref_time || self.proof_size < other.proof_size
323 }
324
325 pub const fn all_lt(self, other: Self) -> bool {
328 self.ref_time < other.ref_time && self.proof_size < other.proof_size
329 }
330
331 pub const fn any_gte(self, other: Self) -> bool {
334 self.ref_time >= other.ref_time || self.proof_size >= other.proof_size
335 }
336
337 pub const fn all_gte(self, other: Self) -> bool {
340 self.ref_time >= other.ref_time && self.proof_size >= other.proof_size
341 }
342
343 pub const fn any_lte(self, other: Self) -> bool {
346 self.ref_time <= other.ref_time || self.proof_size <= other.proof_size
347 }
348
349 pub const fn all_lte(self, other: Self) -> bool {
352 self.ref_time <= other.ref_time && self.proof_size <= other.proof_size
353 }
354
355 pub const fn any_eq(self, other: Self) -> bool {
358 self.ref_time == other.ref_time || self.proof_size == other.proof_size
359 }
360
361 }
363
364impl Zero for Weight {
365 fn zero() -> Self {
366 Self::zero()
367 }
368
369 fn is_zero(&self) -> bool {
370 self == &Self::zero()
371 }
372}
373
374impl Add for Weight {
375 type Output = Self;
376 fn add(self, rhs: Self) -> Self {
377 Self {
378 ref_time: self.ref_time + rhs.ref_time,
379 proof_size: self.proof_size + rhs.proof_size,
380 }
381 }
382}
383
384impl Sub for Weight {
385 type Output = Self;
386 fn sub(self, rhs: Self) -> Self {
387 Self {
388 ref_time: self.ref_time - rhs.ref_time,
389 proof_size: self.proof_size - rhs.proof_size,
390 }
391 }
392}
393
394impl<T> Mul<T> for Weight
395where
396 T: Mul<u64, Output = u64> + Copy,
397{
398 type Output = Self;
399 fn mul(self, b: T) -> Self {
400 Self { ref_time: b * self.ref_time, proof_size: b * self.proof_size }
401 }
402}
403
404#[cfg(any(test, feature = "std", feature = "runtime-benchmarks"))]
405impl From<u64> for Weight {
406 fn from(value: u64) -> Self {
407 Self::from_parts(value, value)
408 }
409}
410
411#[cfg(any(test, feature = "std", feature = "runtime-benchmarks"))]
412impl From<(u64, u64)> for Weight {
413 fn from(value: (u64, u64)) -> Self {
414 Self::from_parts(value.0, value.1)
415 }
416}
417
418macro_rules! weight_mul_per_impl {
419 ($($t:ty),* $(,)?) => {
420 $(
421 impl Mul<Weight> for $t {
422 type Output = Weight;
423 fn mul(self, b: Weight) -> Weight {
424 Weight {
425 ref_time: self * b.ref_time,
426 proof_size: self * b.proof_size,
427 }
428 }
429 }
430 )*
431 }
432}
433weight_mul_per_impl!(
434 sp_arithmetic::Percent,
435 sp_arithmetic::PerU16,
436 sp_arithmetic::Permill,
437 sp_arithmetic::Perbill,
438 sp_arithmetic::Perquintill,
439);
440
441macro_rules! weight_mul_primitive_impl {
442 ($($t:ty),* $(,)?) => {
443 $(
444 impl Mul<Weight> for $t {
445 type Output = Weight;
446 fn mul(self, b: Weight) -> Weight {
447 Weight {
448 ref_time: u64::from(self) * b.ref_time,
449 proof_size: u64::from(self) * b.proof_size,
450 }
451 }
452 }
453 )*
454 }
455}
456weight_mul_primitive_impl!(u8, u16, u32, u64);
457
458impl<T> Div<T> for Weight
459where
460 u64: Div<T, Output = u64>,
461 T: Copy,
462{
463 type Output = Self;
464 fn div(self, b: T) -> Self {
465 Self { ref_time: self.ref_time / b, proof_size: self.proof_size / b }
466 }
467}
468
469impl CheckedAdd for Weight {
470 fn checked_add(&self, rhs: &Self) -> Option<Self> {
471 self.checked_add(rhs)
472 }
473}
474
475impl CheckedSub for Weight {
476 fn checked_sub(&self, rhs: &Self) -> Option<Self> {
477 self.checked_sub(rhs)
478 }
479}
480
481impl core::fmt::Display for Weight {
482 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
483 write!(f, "Weight(ref_time: {}, proof_size: {})", self.ref_time, self.proof_size)
484 }
485}
486
487impl Bounded for Weight {
488 fn min_value() -> Self {
489 Zero::zero()
490 }
491 fn max_value() -> Self {
492 Self::MAX
493 }
494}
495
496impl AddAssign for Weight {
497 fn add_assign(&mut self, other: Self) {
498 *self = Self {
499 ref_time: self.ref_time + other.ref_time,
500 proof_size: self.proof_size + other.proof_size,
501 };
502 }
503}
504
505impl SubAssign for Weight {
506 fn sub_assign(&mut self, other: Self) {
507 *self = Self {
508 ref_time: self.ref_time - other.ref_time,
509 proof_size: self.proof_size - other.proof_size,
510 };
511 }
512}
513
514#[cfg(test)]
515mod tests {
516 use super::*;
517
518 #[test]
519 fn is_zero_works() {
520 assert!(Weight::zero().is_zero());
521 assert!(!Weight::from_parts(1, 0).is_zero());
522 assert!(!Weight::from_parts(0, 1).is_zero());
523 assert!(!Weight::MAX.is_zero());
524 }
525
526 #[test]
527 fn from_parts_works() {
528 assert_eq!(Weight::from_parts(0, 0), Weight { ref_time: 0, proof_size: 0 });
529 assert_eq!(Weight::from_parts(5, 5), Weight { ref_time: 5, proof_size: 5 });
530 assert_eq!(
531 Weight::from_parts(u64::MAX, u64::MAX),
532 Weight { ref_time: u64::MAX, proof_size: u64::MAX }
533 );
534 }
535
536 #[test]
537 fn from_all_works() {
538 assert_eq!(Weight::from_all(0), Weight::from_parts(0, 0));
539 assert_eq!(Weight::from_all(5), Weight::from_parts(5, 5));
540 assert_eq!(Weight::from_all(u64::MAX), Weight::from_parts(u64::MAX, u64::MAX));
541 }
542
543 #[test]
544 fn from_u64_works() {
545 assert_eq!(Weight::from_all(0), 0_u64.into());
546 assert_eq!(Weight::from_all(123), 123_u64.into());
547 assert_eq!(Weight::from_all(u64::MAX), u64::MAX.into());
548 }
549
550 #[test]
551 fn from_u64_pair_works() {
552 assert_eq!(Weight::from_parts(0, 1), (0, 1).into());
553 assert_eq!(Weight::from_parts(123, 321), (123u64, 321u64).into());
554 assert_eq!(Weight::from_parts(u64::MAX, 0), (u64::MAX, 0).into());
555 }
556
557 #[test]
558 fn saturating_reduce_works() {
559 let mut weight = Weight::from_parts(10, 20);
560 weight.saturating_reduce(Weight::from_all(5));
561 assert_eq!(weight, Weight::from_parts(5, 15));
562 weight.saturating_reduce(Weight::from_all(5));
563 assert_eq!(weight, Weight::from_parts(0, 10));
564 weight.saturating_reduce(Weight::from_all(11));
565 assert!(weight.is_zero());
566 weight.saturating_reduce(Weight::from_all(u64::MAX));
567 assert!(weight.is_zero());
568 }
569
570 #[test]
571 fn checked_accrue_works() {
572 let mut weight = Weight::from_parts(10, 20);
573 assert!(weight.checked_accrue(Weight::from_all(2)).is_some());
574 assert_eq!(weight, Weight::from_parts(12, 22));
575 assert!(weight.checked_accrue(Weight::from_parts(u64::MAX, 0)).is_none());
576 assert!(weight.checked_accrue(Weight::from_parts(0, u64::MAX)).is_none());
577 assert_eq!(weight, Weight::from_parts(12, 22));
578 assert!(weight
579 .checked_accrue(Weight::from_parts(u64::MAX - 12, u64::MAX - 22))
580 .is_some());
581 assert_eq!(weight, Weight::MAX);
582 assert!(weight.checked_accrue(Weight::from_parts(1, 0)).is_none());
583 assert!(weight.checked_accrue(Weight::from_parts(0, 1)).is_none());
584 assert_eq!(weight, Weight::MAX);
585 }
586
587 #[test]
588 fn checked_reduce_works() {
589 let mut weight = Weight::from_parts(10, 20);
590 assert!(weight.checked_reduce(Weight::from_all(2)).is_some());
591 assert_eq!(weight, Weight::from_parts(8, 18));
592 assert!(weight.checked_reduce(Weight::from_parts(9, 0)).is_none());
593 assert!(weight.checked_reduce(Weight::from_parts(0, 19)).is_none());
594 assert_eq!(weight, Weight::from_parts(8, 18));
595 assert!(weight.checked_reduce(Weight::from_parts(8, 0)).is_some());
596 assert_eq!(weight, Weight::from_parts(0, 18));
597 assert!(weight.checked_reduce(Weight::from_parts(0, 18)).is_some());
598 assert!(weight.is_zero());
599 }
600
601 #[test]
602 fn checked_div_per_component_works() {
603 assert_eq!(
604 Weight::from_parts(10, 20).checked_div_per_component(&Weight::from_parts(2, 10)),
605 Some(2)
606 );
607 assert_eq!(
608 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 10)),
609 Some(5)
610 );
611 assert_eq!(
612 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 10)),
613 Some(10)
614 );
615 assert_eq!(
616 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(2, 1)),
617 Some(5)
618 );
619 assert_eq!(
620 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 10)),
621 Some(20)
622 );
623 assert_eq!(
624 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(1, 0)),
625 Some(10)
626 );
627 assert_eq!(
628 Weight::from_parts(0, 200).checked_div_per_component(&Weight::from_parts(2, 3)),
629 Some(0)
630 );
631 assert_eq!(
632 Weight::from_parts(10, 0).checked_div_per_component(&Weight::from_parts(2, 3)),
633 Some(0)
634 );
635 assert_eq!(
636 Weight::from_parts(10, 200).checked_div_per_component(&Weight::from_parts(0, 0)),
637 None,
638 );
639 assert_eq!(
640 Weight::from_parts(0, 0).checked_div_per_component(&Weight::from_parts(0, 0)),
641 None,
642 );
643 }
644}