1use core::fmt;
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
7
8#[cfg(feature = "serde")]
9use serde::{Deserialize, Serialize};
10
11pub const WITNESS_SCALE_FACTOR: usize = 4;
13
14#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
19#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "serde", serde(transparent))]
21pub struct Weight(u64);
22
23impl Weight {
24 pub const ZERO: Weight = Weight(0);
28
29 pub const MIN: Weight = Weight(u64::MIN);
33
34 pub const MAX: Weight = Weight(u64::MAX);
36
37 pub const WITNESS_SCALE_FACTOR: u64 = WITNESS_SCALE_FACTOR as u64;
39
40 pub const MAX_BLOCK: Weight = Weight(4_000_000);
42
43 pub const MIN_TRANSACTION: Weight = Weight(Self::WITNESS_SCALE_FACTOR * 60);
45
46 pub const fn from_wu(wu: u64) -> Self { Weight(wu) }
48
49 pub const fn from_wu_usize(wu: usize) -> Self { Weight(wu as u64) }
51
52 pub fn from_kwu(wu: u64) -> Option<Self> { wu.checked_mul(1000).map(Weight) }
54
55 pub fn from_vb(vb: u64) -> Option<Self> {
57 vb.checked_mul(Self::WITNESS_SCALE_FACTOR).map(Weight::from_wu)
58 }
59
60 pub const fn from_vb_unwrap(vb: u64) -> Weight {
66 match vb.checked_mul(Self::WITNESS_SCALE_FACTOR) {
67 Some(weight) => Weight(weight),
68 None => {
69 #[allow(unconditional_panic)]
71 #[allow(clippy::let_unit_value)]
72 #[allow(clippy::out_of_bounds_indexing)]
73 let _int_overflow_scaling_weight = [(); 0][1];
74 Weight(0)
75 }
76 }
77 }
78
79 pub const fn from_vb_unchecked(vb: u64) -> Self { Weight::from_wu(vb * 4) }
81
82 pub const fn from_witness_data_size(witness_size: u64) -> Self { Weight(witness_size) }
84
85 pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self {
87 Weight(non_witness_size * Self::WITNESS_SCALE_FACTOR)
88 }
89
90 pub const fn to_wu(self) -> u64 { self.0 }
94
95 pub const fn to_kwu_floor(self) -> u64 { self.0 / 1000 }
97
98 pub const fn to_vbytes_floor(self) -> u64 { self.0 / Self::WITNESS_SCALE_FACTOR }
100
101 pub const fn to_vbytes_ceil(self) -> u64 {
103 (self.0 + Self::WITNESS_SCALE_FACTOR - 1) / Self::WITNESS_SCALE_FACTOR
104 }
105
106 pub fn checked_add(self, rhs: Self) -> Option<Self> { self.0.checked_add(rhs.0).map(Self) }
110
111 pub fn checked_sub(self, rhs: Self) -> Option<Self> { self.0.checked_sub(rhs.0).map(Self) }
115
116 pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
120
121 pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
125
126 pub fn scale_by_witness_factor(self) -> Option<Self> {
130 Self::checked_mul(self, Self::WITNESS_SCALE_FACTOR)
131 }
132}
133
134impl fmt::Display for Weight {
136 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137 if f.alternate() {
138 write!(f, "{} wu", self.0)
139 } else {
140 fmt::Display::fmt(&self.0, f)
141 }
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn weight_constructor() {
151 assert_eq!(Weight::ZERO, Weight::from_wu(0));
152 assert_eq!(Weight::ZERO, Weight::from_wu_usize(0_usize));
153 }
154
155 #[test]
156 fn kilo_weight_constructor() {
157 assert_eq!(Weight(1_000), Weight::from_kwu(1).expect("expected weight unit"));
158 }
159
160 #[test]
161 #[should_panic]
162 fn kilo_weight_constructor_panic() {
163 Weight::from_kwu(u64::MAX).expect("expected weight unit");
164 }
165
166 #[test]
167 fn from_vb() {
168 let vb = Weight::from_vb(1).expect("expected weight unit");
169 assert_eq!(Weight(4), vb);
170
171 let vb = Weight::from_vb(u64::MAX);
172 assert_eq!(None, vb);
173 }
174
175 #[test]
176 fn from_vb_const() {
177 const WU: Weight = Weight::from_vb_unwrap(1);
178 assert_eq!(Weight(4), WU);
179 }
180
181 #[test]
182 fn from_vb_unchecked() {
183 let vb = Weight::from_vb_unchecked(1);
184 assert_eq!(Weight(4), vb);
185 }
186
187 #[test]
188 #[cfg(debug_assertions)]
189 #[should_panic]
190 fn from_vb_unchecked_panic() { Weight::from_vb_unchecked(u64::MAX); }
191
192 #[test]
193 fn from_witness_data_size() {
194 let witness_data_size = 1;
195 assert_eq!(Weight(witness_data_size), Weight::from_witness_data_size(witness_data_size));
196 }
197
198 #[test]
199 fn from_non_witness_data_size() {
200 assert_eq!(Weight(4), Weight::from_non_witness_data_size(1));
201 }
202
203 #[test]
204 fn to_kwu_floor() {
205 assert_eq!(1, Weight(1_000).to_kwu_floor());
206 }
207
208 #[test]
209 fn to_vb_floor() {
210 assert_eq!(1, Weight(4).to_vbytes_floor());
211 assert_eq!(1, Weight(5).to_vbytes_floor());
212 }
213
214 #[test]
215 fn to_vb_ceil() {
216 assert_eq!(1, Weight(4).to_vbytes_ceil());
217 assert_eq!(2, Weight(5).to_vbytes_ceil());
218 }
219
220 #[test]
221 fn checked_add() {
222 let result = Weight(1).checked_add(Weight(1)).expect("expected weight unit");
223 assert_eq!(Weight(2), result);
224
225 let result = Weight::MAX.checked_add(Weight(1));
226 assert_eq!(None, result);
227 }
228
229 #[test]
230 fn checked_sub() {
231 let result = Weight(1).checked_sub(Weight(1)).expect("expected weight unit");
232 assert_eq!(Weight::ZERO, result);
233
234 let result = Weight::MIN.checked_sub(Weight(1));
235 assert_eq!(None, result);
236 }
237
238 #[test]
239 fn checked_mul() {
240 let result = Weight(2).checked_mul(2).expect("expected weight unit");
241 assert_eq!(Weight(4), result);
242
243 let result = Weight::MAX.checked_mul(2);
244 assert_eq!(None, result);
245 }
246
247 #[test]
248 fn checked_div() {
249 let result = Weight(2).checked_div(2).expect("expected weight unit");
250 assert_eq!(Weight(1), result);
251
252 let result = Weight(2).checked_div(0);
253 assert_eq!(None, result);
254 }
255
256 #[test]
257 fn scale_by_witness_factor() {
258 let result = Weight(1).scale_by_witness_factor().expect("expected weight unit");
259 assert_eq!(Weight(4), result);
260
261 let result = Weight::MAX.scale_by_witness_factor();
262 assert_eq!(None, result);
263 }
264}
265
266impl From<Weight> for u64 {
267 fn from(value: Weight) -> Self { value.to_wu() }
268}
269
270impl Add for Weight {
271 type Output = Weight;
272
273 fn add(self, rhs: Weight) -> Self::Output { Weight(self.0 + rhs.0) }
274}
275
276impl AddAssign for Weight {
277 fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
278}
279
280impl Sub for Weight {
281 type Output = Weight;
282
283 fn sub(self, rhs: Weight) -> Self::Output { Weight(self.0 - rhs.0) }
284}
285
286impl SubAssign for Weight {
287 fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
288}
289
290impl Mul<u64> for Weight {
291 type Output = Weight;
292
293 fn mul(self, rhs: u64) -> Self::Output { Weight(self.0 * rhs) }
294}
295
296impl Mul<Weight> for u64 {
297 type Output = Weight;
298
299 fn mul(self, rhs: Weight) -> Self::Output { Weight(self * rhs.0) }
300}
301
302impl MulAssign<u64> for Weight {
303 fn mul_assign(&mut self, rhs: u64) { self.0 *= rhs }
304}
305
306impl Div<u64> for Weight {
307 type Output = Weight;
308
309 fn div(self, rhs: u64) -> Self::Output { Weight(self.0 / rhs) }
310}
311
312impl Div<Weight> for Weight {
313 type Output = u64;
314
315 fn div(self, rhs: Weight) -> Self::Output { self.to_wu() / rhs.to_wu() }
316}
317
318impl DivAssign<u64> for Weight {
319 fn div_assign(&mut self, rhs: u64) { self.0 /= rhs }
320}
321
322impl core::iter::Sum for Weight {
323 fn sum<I>(iter: I) -> Self
324 where
325 I: Iterator<Item = Self>,
326 {
327 Weight(iter.map(Weight::to_wu).sum())
328 }
329}
330
331impl<'a> core::iter::Sum<&'a Weight> for Weight {
332 fn sum<I>(iter: I) -> Self
333 where
334 I: Iterator<Item = &'a Weight>,
335 {
336 iter.cloned().sum()
337 }
338}
339
340crate::impl_parse_str_from_int_infallible!(Weight, u64, from_wu);