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 => panic!("checked_mul overflowed"),
71 }
72 }
73
74 pub const fn from_vb_unchecked(vb: u64) -> Self { Weight::from_wu(vb * 4) }
76
77 pub const fn from_witness_data_size(witness_size: u64) -> Self { Weight(witness_size) }
79
80 pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self {
82 Weight(non_witness_size * Self::WITNESS_SCALE_FACTOR)
83 }
84
85 pub const fn to_wu(self) -> u64 { self.0 }
89
90 pub const fn to_kwu_floor(self) -> u64 { self.0 / 1000 }
92
93 pub const fn to_vbytes_floor(self) -> u64 { self.0 / Self::WITNESS_SCALE_FACTOR }
95
96 pub const fn to_vbytes_ceil(self) -> u64 {
98 (self.0 + Self::WITNESS_SCALE_FACTOR - 1) / Self::WITNESS_SCALE_FACTOR
99 }
100
101 pub fn checked_add(self, rhs: Self) -> Option<Self> { self.0.checked_add(rhs.0).map(Self) }
105
106 pub fn checked_sub(self, rhs: Self) -> Option<Self> { self.0.checked_sub(rhs.0).map(Self) }
110
111 pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
115
116 pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
120}
121
122impl fmt::Display for Weight {
124 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125 if f.alternate() {
126 write!(f, "{} wu", self.0)
127 } else {
128 fmt::Display::fmt(&self.0, f)
129 }
130 }
131}
132
133impl From<Weight> for u64 {
134 fn from(value: Weight) -> Self { value.to_wu() }
135}
136
137impl Add for Weight {
138 type Output = Weight;
139
140 fn add(self, rhs: Weight) -> Self::Output { Weight(self.0 + rhs.0) }
141}
142
143impl AddAssign for Weight {
144 fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
145}
146
147impl Sub for Weight {
148 type Output = Weight;
149
150 fn sub(self, rhs: Weight) -> Self::Output { Weight(self.0 - rhs.0) }
151}
152
153impl SubAssign for Weight {
154 fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
155}
156
157impl Mul<u64> for Weight {
158 type Output = Weight;
159
160 fn mul(self, rhs: u64) -> Self::Output { Weight(self.0 * rhs) }
161}
162
163impl Mul<Weight> for u64 {
164 type Output = Weight;
165
166 fn mul(self, rhs: Weight) -> Self::Output { Weight(self * rhs.0) }
167}
168
169impl MulAssign<u64> for Weight {
170 fn mul_assign(&mut self, rhs: u64) { self.0 *= rhs }
171}
172
173impl Div<u64> for Weight {
174 type Output = Weight;
175
176 fn div(self, rhs: u64) -> Self::Output { Weight(self.0 / rhs) }
177}
178
179impl Div<Weight> for Weight {
180 type Output = u64;
181
182 fn div(self, rhs: Weight) -> Self::Output { self.to_wu() / rhs.to_wu() }
183}
184
185impl DivAssign<u64> for Weight {
186 fn div_assign(&mut self, rhs: u64) { self.0 /= rhs }
187}
188
189impl core::iter::Sum for Weight {
190 fn sum<I>(iter: I) -> Self
191 where
192 I: Iterator<Item = Self>,
193 {
194 Weight(iter.map(Weight::to_wu).sum())
195 }
196}
197
198impl<'a> core::iter::Sum<&'a Weight> for Weight {
199 fn sum<I>(iter: I) -> Self
200 where
201 I: Iterator<Item = &'a Weight>,
202 {
203 iter.cloned().sum()
204 }
205}
206
207crate::impl_parse_str_from_int_infallible!(Weight, u64, from_wu);
208
209#[cfg(feature = "arbitrary")]
210impl<'a> Arbitrary<'a> for Weight {
211 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
212 let w = u64::arbitrary(u)?;
213 Ok(Weight(w))
214 }
215}
216
217#[cfg(test)]
218mod tests {
219 use super::*;
220
221 #[test]
222 fn weight_constructor() {
223 assert_eq!(Weight::ZERO, Weight::from_wu(0));
224 assert_eq!(Weight::ZERO, Weight::from_wu_usize(0_usize));
225 }
226
227 #[test]
228 fn kilo_weight_constructor() {
229 assert_eq!(Weight(1_000), Weight::from_kwu(1).expect("expected weight unit"));
230 }
231
232 #[test]
233 #[should_panic]
234 fn kilo_weight_constructor_panic() {
235 Weight::from_kwu(u64::MAX).expect("expected weight unit");
236 }
237
238 #[test]
239 fn from_vb() {
240 let w = Weight::from_vb(1).expect("expected weight unit");
241 assert_eq!(Weight(4), w);
242
243 let w = Weight::from_vb(u64::MAX);
244 assert_eq!(None, w);
245 }
246
247 #[test]
248 fn from_vb_const() {
249 const WU: Weight = Weight::from_vb_unwrap(1);
250 assert_eq!(Weight(4), WU);
251 }
252
253 #[test]
254 fn from_vb_unchecked() {
255 let w = Weight::from_vb_unchecked(1);
256 assert_eq!(Weight(4), w);
257 }
258
259 #[test]
260 #[cfg(debug_assertions)]
261 #[should_panic]
262 fn from_vb_unchecked_panic() { Weight::from_vb_unchecked(u64::MAX); }
263
264 #[test]
265 fn from_witness_data_size() {
266 let witness_data_size = 1;
267 assert_eq!(Weight(witness_data_size), Weight::from_witness_data_size(witness_data_size));
268 }
269
270 #[test]
271 fn from_non_witness_data_size() {
272 assert_eq!(Weight(4), Weight::from_non_witness_data_size(1));
273 }
274
275 #[test]
276 fn to_kwu_floor() {
277 assert_eq!(1, Weight(1_000).to_kwu_floor());
278 }
279
280 #[test]
281 fn to_vb_floor() {
282 assert_eq!(1, Weight(4).to_vbytes_floor());
283 assert_eq!(1, Weight(5).to_vbytes_floor());
284 }
285
286 #[test]
287 fn to_vb_ceil() {
288 assert_eq!(1, Weight(4).to_vbytes_ceil());
289 assert_eq!(2, Weight(5).to_vbytes_ceil());
290 }
291
292 #[test]
293 fn checked_add() {
294 let result = Weight(1).checked_add(Weight(1)).expect("expected weight unit");
295 assert_eq!(Weight(2), result);
296
297 let result = Weight::MAX.checked_add(Weight(1));
298 assert_eq!(None, result);
299 }
300
301 #[test]
302 fn checked_sub() {
303 let result = Weight(1).checked_sub(Weight(1)).expect("expected weight unit");
304 assert_eq!(Weight::ZERO, result);
305
306 let result = Weight::MIN.checked_sub(Weight(1));
307 assert_eq!(None, result);
308 }
309
310 #[test]
311 fn checked_mul() {
312 let result = Weight(2).checked_mul(2).expect("expected weight unit");
313 assert_eq!(Weight(4), result);
314
315 let result = Weight::MAX.checked_mul(2);
316 assert_eq!(None, result);
317 }
318
319 #[test]
320 fn checked_div() {
321 let result = Weight(2).checked_div(2).expect("expected weight unit");
322 assert_eq!(Weight(1), result);
323
324 let result = Weight(2).checked_div(0);
325 assert_eq!(None, result);
326 }
327}