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