ckb_gen_types/extension/capacity.rs
1use ckb_occupied_capacity::{Capacity, Result as CapacityResult};
2
3use crate::{packed, prelude::*};
4
5impl packed::Script {
6 /// Calculates the occupied capacity of [`Script`].
7 ///
8 /// Includes [`code_hash`] (32), [`hash_type`] (1) and [`args`] (calculated).
9 ///
10 /// [`Script`]: https://github.com/nervosnetwork/ckb/blob/v0.36.0/util/types/schemas/blockchain.mol#L30-L34
11 /// [`code_hash`]: #method.code_hash
12 /// [`hash_type`]: #method.hash_type
13 /// [`args`]: #method.args
14 pub fn occupied_capacity(&self) -> CapacityResult<Capacity> {
15 Capacity::bytes(self.args().raw_data().len() + 32 + 1)
16 }
17}
18
19impl packed::CellOutput {
20 /// Calculates the occupied capacity of [`CellOutput`].
21 ///
22 /// Includes [`output_data`] (provided), [`capacity`] (8), [`lock`] (calculated) and [`type`] (calculated).
23 ///
24 /// [`CellOutput`]: https://github.com/nervosnetwork/ckb/blob/v0.36.0/util/types/schemas/blockchain.mol#L46-L50
25 /// [`output_data`]: https://github.com/nervosnetwork/ckb/blob/v0.36.0/util/types/schemas/blockchain.mol#L63
26 /// [`capacity`]: #method.capacity
27 /// [`lock`]: #method.lock
28 /// [`type`]: #method.type_
29 pub fn occupied_capacity(&self, data_capacity: Capacity) -> CapacityResult<Capacity> {
30 Capacity::bytes(8)
31 .and_then(|x| x.safe_add(data_capacity))
32 .and_then(|x| self.lock().occupied_capacity().and_then(|y| y.safe_add(x)))
33 .and_then(|x| {
34 self.type_()
35 .to_opt()
36 .as_ref()
37 .map(packed::Script::occupied_capacity)
38 .transpose()
39 .and_then(|y| y.unwrap_or_else(Capacity::zero).safe_add(x))
40 })
41 }
42
43 /// Returns if the [`capacity`] in `CellOutput` is smaller than the [`occupied capacity`].
44 ///
45 /// [`capacity`]: #method.capacity
46 /// [`occupied capacity`]: #method.occupied_capacity
47 pub fn is_lack_of_capacity(&self, data_capacity: Capacity) -> CapacityResult<bool> {
48 self.occupied_capacity(data_capacity)
49 .map(|cap| cap > self.capacity().unpack())
50 }
51}
52
53impl packed::CellOutputBuilder {
54 /// Build a [`CellOutput`] and sets its [`capacity`] equal to its [`occupied capacity`] exactly.
55 ///
56 /// [`CellOutput`]: struct.CellOutput.html
57 /// [`capacity`]: #method.capacity
58 /// [`occupied capacity`]: struct.CellOutput.html#method.occupied_capacity
59 pub fn build_exact_capacity(
60 self,
61 data_capacity: Capacity,
62 ) -> CapacityResult<packed::CellOutput> {
63 Capacity::bytes(8)
64 .and_then(|x| x.safe_add(data_capacity))
65 .and_then(|x| self.lock.occupied_capacity().and_then(|y| y.safe_add(x)))
66 .and_then(|x| {
67 self.type_
68 .to_opt()
69 .as_ref()
70 .map(packed::Script::occupied_capacity)
71 .transpose()
72 .and_then(|y| y.unwrap_or_else(Capacity::zero).safe_add(x))
73 })
74 .map(|x| self.capacity(x.pack()).build())
75 }
76}
77
78impl packed::CellOutputVec {
79 /// Sums the capacities of all [`CellOutput`]s in the vector.
80 ///
81 /// [`CellOutput`]: struct.CellOutput.html#method.occupied_capacity
82 pub fn total_capacity(&self) -> CapacityResult<Capacity> {
83 self.as_reader()
84 .iter()
85 .map(|output| {
86 let cap: Capacity = output.capacity().unpack();
87 cap
88 })
89 .try_fold(Capacity::zero(), Capacity::safe_add)
90 }
91}