sp_weights/
weight_v2.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use 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	/// The weight of computational time used based on some reference hardware.
42	ref_time: u64,
43	#[codec(compact)]
44	/// The weight of storage space used by proof of validity.
45	proof_size: u64,
46}
47
48impl Weight {
49	/// Set the reference time part of the weight.
50	pub const fn set_ref_time(mut self, c: u64) -> Self {
51		self.ref_time = c;
52		self
53	}
54
55	/// Set the storage size part of the weight.
56	pub const fn set_proof_size(mut self, c: u64) -> Self {
57		self.proof_size = c;
58		self
59	}
60
61	/// Return the reference time part of the weight.
62	pub const fn ref_time(&self) -> u64 {
63		self.ref_time
64	}
65
66	/// Return the storage size part of the weight.
67	pub const fn proof_size(&self) -> u64 {
68		self.proof_size
69	}
70
71	/// Return a mutable reference to the reference time part of the weight.
72	pub fn ref_time_mut(&mut self) -> &mut u64 {
73		&mut self.ref_time
74	}
75
76	/// Return a mutable reference to the storage size part of the weight.
77	pub fn proof_size_mut(&mut self) -> &mut u64 {
78		&mut self.proof_size
79	}
80
81	/// The maximal weight in all dimensions.
82	pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX };
83
84	/// Get the conservative min of `self` and `other` weight.
85	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	/// Get the aggressive max of `self` and `other` weight.
93	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	/// Try to add some `other` weight while upholding the `limit`.
101	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	/// Construct [`Weight`] from weight parts, namely reference time and proof size weights.
111	pub const fn from_parts(ref_time: u64, proof_size: u64) -> Self {
112		Self { ref_time, proof_size }
113	}
114
115	/// Construct [`Weight`] from the same weight for all parts.
116	pub const fn from_all(value: u64) -> Self {
117		Self { ref_time: value, proof_size: value }
118	}
119
120	/// Saturating [`Weight`] addition. Computes `self + rhs`, saturating at the numeric bounds of
121	/// all fields instead of overflowing.
122	#[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	/// Saturating [`Weight`] subtraction. Computes `self - rhs`, saturating at the numeric bounds
131	/// of all fields instead of overflowing.
132	#[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	/// Saturating [`Weight`] scalar multiplication. Computes `self.field * scalar` for all fields,
141	/// saturating at the numeric bounds of all fields instead of overflowing.
142	#[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	/// Saturating [`Weight`] scalar division. Computes `self.field / scalar` for all fields,
151	/// saturating at the numeric bounds of all fields instead of overflowing.
152	#[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	/// Saturating [`Weight`] scalar exponentiation. Computes `self.field.pow(exp)` for all fields,
161	/// saturating at the numeric bounds of all fields instead of overflowing.
162	#[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	/// Increment [`Weight`] by `amount` via saturating addition.
171	pub fn saturating_accrue(&mut self, amount: Self) {
172		*self = self.saturating_add(amount);
173	}
174
175	/// Reduce [`Weight`] by `amount` via saturating subtraction.
176	pub fn saturating_reduce(&mut self, amount: Self) {
177		*self = self.saturating_sub(amount);
178	}
179
180	/// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred.
181	#[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	/// Checked [`Weight`] subtraction. Computes `self - rhs`, returning `None` if overflow
195	/// occurred.
196	#[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	/// Checked [`Weight`] scalar multiplication. Computes `self.field * scalar` for each field,
210	/// returning `None` if overflow occurred.
211	#[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	/// Checked [`Weight`] scalar division. Computes `self.field / scalar` for each field, returning
225	/// `None` if overflow occurred.
226	#[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	/// Calculates how many `other` fit into `self`.
240	///
241	/// Divides each component of `self` against the same component of `other`. Returns the minimum
242	/// of all those divisions. Returns `None` in case **all** components of `other` are zero.
243	///
244	/// This returns `Some` even if some components of `other` are zero as long as there is at least
245	/// one non-zero component in `other`. The division for this particular component will then
246	/// yield the maximum value (e.g u64::MAX). This is because we assume not every operation and
247	/// hence each `Weight` will necessarily use each resource.
248	#[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	/// Try to increase `self` by `amount` via checked addition.
273	pub fn checked_accrue(&mut self, amount: Self) -> Option<()> {
274		self.checked_add(&amount).map(|new_self| *self = new_self)
275	}
276
277	/// Try to reduce `self` by `amount` via checked subtraction.
278	pub fn checked_reduce(&mut self, amount: Self) -> Option<()> {
279		self.checked_sub(&amount).map(|new_self| *self = new_self)
280	}
281
282	/// Return a [`Weight`] where all fields are zero.
283	pub const fn zero() -> Self {
284		Self { ref_time: 0, proof_size: 0 }
285	}
286
287	/// Constant version of Add for `ref_time` component with u64.
288	///
289	/// Is only overflow safe when evaluated at compile-time.
290	#[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	/// Constant version of Add for `proof_size` component with u64.
296	///
297	/// Is only overflow safe when evaluated at compile-time.
298	#[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	/// Constant version of Sub for `ref_time` component with u64.
304	///
305	/// Is only overflow safe when evaluated at compile-time.
306	#[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	/// Constant version of Sub for `proof_size` component with u64.
312	///
313	/// Is only overflow safe when evaluated at compile-time.
314	#[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	/// Saturating version of Add for `ref_time` component with u64.
320	#[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	/// Saturating version of Add for `proof_size` component with u64.
326	#[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	/// Saturating version of Sub for `ref_time` component with u64.
332	#[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	/// Saturating version of Sub for `proof_size` component with u64.
338	#[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	/// Constant version of Div with u64.
344	///
345	/// Is only overflow safe when evaluated at compile-time.
346	#[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	/// Constant version of Mul with u64.
352	///
353	/// Is only overflow safe when evaluated at compile-time.
354	#[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	/// Returns true if any of `self`'s constituent weights is strictly greater than that of the
360	/// `other`'s, otherwise returns false.
361	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	/// Returns true if all of `self`'s constituent weights is strictly greater than that of the
366	/// `other`'s, otherwise returns false.
367	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	/// Returns true if any of `self`'s constituent weights is strictly less than that of the
372	/// `other`'s, otherwise returns false.
373	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	/// Returns true if all of `self`'s constituent weights is strictly less than that of the
378	/// `other`'s, otherwise returns false.
379	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	/// Returns true if any of `self`'s constituent weights is greater than or equal to that of the
384	/// `other`'s, otherwise returns false.
385	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	/// Returns true if all of `self`'s constituent weights is greater than or equal to that of the
390	/// `other`'s, otherwise returns false.
391	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	/// Returns true if any of `self`'s constituent weights is less than or equal to that of the
396	/// `other`'s, otherwise returns false.
397	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	/// Returns true if all of `self`'s constituent weights is less than or equal to that of the
402	/// `other`'s, otherwise returns false.
403	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	/// Returns true if any of `self`'s constituent weights is equal to that of the `other`'s,
408	/// otherwise returns false.
409	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	// NOTE: `all_eq` does not exist, as it's simply the `eq` method from the `PartialEq` trait.
414}
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		// Normal addition
700		let weight = Weight::from_parts(10, 20);
701		assert_eq!(weight.saturating_add_ref_time(5), Weight::from_parts(15, 20));
702
703		// Saturation at MAX
704		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		// Already at MAX
708		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		// Adding zero
712		let weight = Weight::from_parts(10, 20);
713		assert_eq!(weight.saturating_add_ref_time(0), Weight::from_parts(10, 20));
714
715		// Proof size remains unchanged
716		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		// Normal addition
723		let weight = Weight::from_parts(10, 20);
724		assert_eq!(weight.saturating_add_proof_size(5), Weight::from_parts(10, 25));
725
726		// Saturation at MAX
727		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		// Already at MAX
731		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		// Adding zero
735		let weight = Weight::from_parts(10, 20);
736		assert_eq!(weight.saturating_add_proof_size(0), Weight::from_parts(10, 20));
737
738		// Ref time remains unchanged
739		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		// Normal subtraction
746		let weight = Weight::from_parts(10, 20);
747		assert_eq!(weight.saturating_sub_ref_time(5), Weight::from_parts(5, 20));
748
749		// Saturation at zero (underflow)
750		let weight = Weight::from_parts(5, 20);
751		assert_eq!(weight.saturating_sub_ref_time(10), Weight::from_parts(0, 20));
752
753		// Already at zero
754		let weight = Weight::from_parts(0, 20);
755		assert_eq!(weight.saturating_sub_ref_time(1), Weight::from_parts(0, 20));
756
757		// Subtracting zero
758		let weight = Weight::from_parts(10, 20);
759		assert_eq!(weight.saturating_sub_ref_time(0), Weight::from_parts(10, 20));
760
761		// Exact subtraction to zero
762		let weight = Weight::from_parts(10, 20);
763		assert_eq!(weight.saturating_sub_ref_time(10), Weight::from_parts(0, 20));
764
765		// Proof size remains unchanged
766		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		// Normal subtraction
773		let weight = Weight::from_parts(10, 20);
774		assert_eq!(weight.saturating_sub_proof_size(5), Weight::from_parts(10, 15));
775
776		// Saturation at zero (underflow)
777		let weight = Weight::from_parts(10, 5);
778		assert_eq!(weight.saturating_sub_proof_size(10), Weight::from_parts(10, 0));
779
780		// Already at zero
781		let weight = Weight::from_parts(10, 0);
782		assert_eq!(weight.saturating_sub_proof_size(1), Weight::from_parts(10, 0));
783
784		// Subtracting zero
785		let weight = Weight::from_parts(10, 20);
786		assert_eq!(weight.saturating_sub_proof_size(0), Weight::from_parts(10, 20));
787
788		// Exact subtraction to zero
789		let weight = Weight::from_parts(10, 20);
790		assert_eq!(weight.saturating_sub_proof_size(20), Weight::from_parts(10, 0));
791
792		// Ref time remains unchanged
793		let weight = Weight::from_parts(42, 20);
794		assert_eq!(weight.saturating_sub_proof_size(5).ref_time(), 42);
795	}
796}