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}