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	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	/// Saturating [`Weight`] subtraction. Computes `self - rhs`, saturating at the numeric bounds
130	/// of all fields instead of overflowing.
131	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	/// Saturating [`Weight`] scalar multiplication. Computes `self.field * scalar` for all fields,
139	/// saturating at the numeric bounds of all fields instead of overflowing.
140	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	/// Saturating [`Weight`] scalar division. Computes `self.field / scalar` for all fields,
148	/// saturating at the numeric bounds of all fields instead of overflowing.
149	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	/// Saturating [`Weight`] scalar exponentiation. Computes `self.field.pow(exp)` for all fields,
157	/// saturating at the numeric bounds of all fields instead of overflowing.
158	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	/// Increment [`Weight`] by `amount` via saturating addition.
166	pub fn saturating_accrue(&mut self, amount: Self) {
167		*self = self.saturating_add(amount);
168	}
169
170	/// Reduce [`Weight`] by `amount` via saturating subtraction.
171	pub fn saturating_reduce(&mut self, amount: Self) {
172		*self = self.saturating_sub(amount);
173	}
174
175	/// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred.
176	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	/// Checked [`Weight`] subtraction. Computes `self - rhs`, returning `None` if overflow
189	/// occurred.
190	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	/// Checked [`Weight`] scalar multiplication. Computes `self.field * scalar` for each field,
203	/// returning `None` if overflow occurred.
204	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	/// Checked [`Weight`] scalar division. Computes `self.field / scalar` for each field, returning
217	/// `None` if overflow occurred.
218	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	/// Calculates how many `other` fit into `self`.
231	///
232	/// Divides each component of `self` against the same component of `other`. Returns the minimum
233	/// of all those divisions. Returns `None` in case **all** components of `other` are zero.
234	///
235	/// This returns `Some` even if some components of `other` are zero as long as there is at least
236	/// one non-zero component in `other`. The division for this particular component will then
237	/// yield the maximum value (e.g u64::MAX). This is because we assume not every operation and
238	/// hence each `Weight` will necessarily use each resource.
239	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	/// Try to increase `self` by `amount` via checked addition.
263	pub fn checked_accrue(&mut self, amount: Self) -> Option<()> {
264		self.checked_add(&amount).map(|new_self| *self = new_self)
265	}
266
267	/// Try to reduce `self` by `amount` via checked subtraction.
268	pub fn checked_reduce(&mut self, amount: Self) -> Option<()> {
269		self.checked_sub(&amount).map(|new_self| *self = new_self)
270	}
271
272	/// Return a [`Weight`] where all fields are zero.
273	pub const fn zero() -> Self {
274		Self { ref_time: 0, proof_size: 0 }
275	}
276
277	/// Constant version of Add for `ref_time` component with u64.
278	///
279	/// Is only overflow safe when evaluated at compile-time.
280	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	/// Constant version of Add for `proof_size` component with u64.
285	///
286	/// Is only overflow safe when evaluated at compile-time.
287	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	/// Constant version of Sub for `ref_time` component with u64.
292	///
293	/// Is only overflow safe when evaluated at compile-time.
294	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	/// Constant version of Sub for `proof_size` component with u64.
299	///
300	/// Is only overflow safe when evaluated at compile-time.
301	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	/// Saturating version of Add for `ref_time` component with u64.
306	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	/// Saturating version of Add for `proof_size` component with u64.
311	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	/// Saturating version of Sub for `ref_time` component with u64.
316	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	/// Saturating version of Sub for `proof_size` component with u64.
321	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	/// Constant version of Div with u64.
326	///
327	/// Is only overflow safe when evaluated at compile-time.
328	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	/// Constant version of Mul with u64.
333	///
334	/// Is only overflow safe when evaluated at compile-time.
335	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	/// Returns true if any of `self`'s constituent weights is strictly greater than that of the
340	/// `other`'s, otherwise returns false.
341	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	/// Returns true if all of `self`'s constituent weights is strictly greater than that of the
346	/// `other`'s, otherwise returns false.
347	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	/// Returns true if any of `self`'s constituent weights is strictly less than that of the
352	/// `other`'s, otherwise returns false.
353	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	/// Returns true if all of `self`'s constituent weights is strictly less than that of the
358	/// `other`'s, otherwise returns false.
359	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	/// Returns true if any of `self`'s constituent weights is greater than or equal to that of the
364	/// `other`'s, otherwise returns false.
365	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	/// Returns true if all of `self`'s constituent weights is greater than or equal to that of the
370	/// `other`'s, otherwise returns false.
371	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	/// Returns true if any of `self`'s constituent weights is less than or equal to that of the
376	/// `other`'s, otherwise returns false.
377	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	/// Returns true if all of `self`'s constituent weights is less than or equal to that of the
382	/// `other`'s, otherwise returns false.
383	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	/// Returns true if any of `self`'s constituent weights is equal to that of the `other`'s,
388	/// otherwise returns false.
389	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	// NOTE: `all_eq` does not exist, as it's simply the `eq` method from the `PartialEq` trait.
394}
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		// Normal addition
680		let weight = Weight::from_parts(10, 20);
681		assert_eq!(weight.saturating_add_ref_time(5), Weight::from_parts(15, 20));
682
683		// Saturation at MAX
684		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		// Already at MAX
688		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		// Adding zero
692		let weight = Weight::from_parts(10, 20);
693		assert_eq!(weight.saturating_add_ref_time(0), Weight::from_parts(10, 20));
694
695		// Proof size remains unchanged
696		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		// Normal addition
703		let weight = Weight::from_parts(10, 20);
704		assert_eq!(weight.saturating_add_proof_size(5), Weight::from_parts(10, 25));
705
706		// Saturation at MAX
707		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		// Already at MAX
711		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		// Adding zero
715		let weight = Weight::from_parts(10, 20);
716		assert_eq!(weight.saturating_add_proof_size(0), Weight::from_parts(10, 20));
717
718		// Ref time remains unchanged
719		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		// Normal subtraction
726		let weight = Weight::from_parts(10, 20);
727		assert_eq!(weight.saturating_sub_ref_time(5), Weight::from_parts(5, 20));
728
729		// Saturation at zero (underflow)
730		let weight = Weight::from_parts(5, 20);
731		assert_eq!(weight.saturating_sub_ref_time(10), Weight::from_parts(0, 20));
732
733		// Already at zero
734		let weight = Weight::from_parts(0, 20);
735		assert_eq!(weight.saturating_sub_ref_time(1), Weight::from_parts(0, 20));
736
737		// Subtracting zero
738		let weight = Weight::from_parts(10, 20);
739		assert_eq!(weight.saturating_sub_ref_time(0), Weight::from_parts(10, 20));
740
741		// Exact subtraction to zero
742		let weight = Weight::from_parts(10, 20);
743		assert_eq!(weight.saturating_sub_ref_time(10), Weight::from_parts(0, 20));
744
745		// Proof size remains unchanged
746		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		// Normal subtraction
753		let weight = Weight::from_parts(10, 20);
754		assert_eq!(weight.saturating_sub_proof_size(5), Weight::from_parts(10, 15));
755
756		// Saturation at zero (underflow)
757		let weight = Weight::from_parts(10, 5);
758		assert_eq!(weight.saturating_sub_proof_size(10), Weight::from_parts(10, 0));
759
760		// Already at zero
761		let weight = Weight::from_parts(10, 0);
762		assert_eq!(weight.saturating_sub_proof_size(1), Weight::from_parts(10, 0));
763
764		// Subtracting zero
765		let weight = Weight::from_parts(10, 20);
766		assert_eq!(weight.saturating_sub_proof_size(0), Weight::from_parts(10, 20));
767
768		// Exact subtraction to zero
769		let weight = Weight::from_parts(10, 20);
770		assert_eq!(weight.saturating_sub_proof_size(20), Weight::from_parts(10, 0));
771
772		// Ref time remains unchanged
773		let weight = Weight::from_parts(42, 20);
774		assert_eq!(weight.saturating_sub_proof_size(5).ref_time(), 42);
775	}
776}