ckb_sdk/core/
advanced_builders.rs

1use ckb_types::{constants, core, packed, prelude::*};
2use derive_getters::Getters;
3
4/// An advanced builder for [`TransactionView`].
5///
6/// Base on [`packed::TransactionBuilder`] but added lots of syntactic sugar.
7///
8/// [`TransactionView`]: struct.TransactionView.html
9/// [`packed::TransactionBuilder`]: ../packed/struct.TransactionBuilder.html
10#[derive(Clone, Debug, Getters)]
11pub struct TransactionBuilder {
12    #[getter(skip)]
13    pub version: packed::Uint32,
14    #[getter(rename = "get_cell_deps")]
15    pub cell_deps: Vec<packed::CellDep>,
16    #[getter(rename = "get_header_deps")]
17    pub header_deps: Vec<packed::Byte32>,
18    #[getter(rename = "get_inputs")]
19    pub inputs: Vec<packed::CellInput>,
20    #[getter(rename = "get_outputs")]
21    pub outputs: Vec<packed::CellOutput>,
22    #[getter(rename = "get_witnesses")]
23    pub witnesses: Vec<packed::Bytes>,
24    #[getter(rename = "get_outputs_data")]
25    pub outputs_data: Vec<packed::Bytes>,
26}
27
28/*
29 * Implement std traits.
30 */
31impl ::std::default::Default for TransactionBuilder {
32    fn default() -> Self {
33        Self {
34            version: constants::TX_VERSION.pack(),
35            cell_deps: Default::default(),
36            header_deps: Default::default(),
37            inputs: Default::default(),
38            outputs: Default::default(),
39            witnesses: Default::default(),
40            outputs_data: Default::default(),
41        }
42    }
43}
44
45macro_rules! def_setter_simple {
46    (__add_doc, $prefix:ident, $field:ident, $type:ident, $comment:expr) => {
47        #[doc = $comment]
48        pub fn $field(mut self, v: packed::$type) -> Self {
49            self.$prefix.$field = v;
50            self
51        }
52    };
53    (__add_doc, $field:ident, $type:ident, $comment:expr) => {
54        #[doc = $comment]
55        pub fn $field(mut self, v: packed::$type) -> Self {
56            self.$field = v;
57            self
58        }
59    };
60    ($prefix:ident, $field:ident, $type:ident) => {
61        def_setter_simple!(
62            __add_doc,
63            $prefix,
64            $field,
65            $type,
66            concat!("Sets `", stringify!($prefix), ".", stringify!($field), "`.")
67        );
68    };
69    ($field:ident, $type:ident) => {
70        def_setter_simple!(
71            __add_doc,
72            $field,
73            $type,
74            concat!("Sets `", stringify!($field), "`.")
75        );
76    };
77}
78
79macro_rules! def_setter_for_vector {
80    (
81        $prefix:ident, $field:ident, $type:ident,
82        $func_push:ident, $func_extend:ident, $func_set:ident,
83        $comment_push:expr, $comment_extend:expr, $comment_set:expr,
84    ) => {
85        #[doc = $comment_push]
86        pub fn $func_push(&mut self, v: $prefix::$type) -> &mut Self {
87            self.$field.push(v);
88            self
89        }
90        #[doc = $comment_extend]
91        pub fn $func_extend<T>(&mut self, v: T) -> &mut Self
92        where
93            T: ::std::iter::IntoIterator<Item = $prefix::$type>,
94        {
95            self.$field.extend(v);
96            self
97        }
98        #[doc = $comment_set]
99        pub fn $func_set(&mut self, v: Vec<$prefix::$type>) -> &mut Self {
100            self.$field = v;
101            self
102        }
103    };
104    ($prefix:ident, $field:ident, $type:ident, $func_push:ident, $func_extend:ident, $func_set:ident) => {
105        def_setter_for_vector!(
106            $prefix,
107            $field,
108            $type,
109            $func_push,
110            $func_extend,
111            $func_set,
112            concat!("Pushes an item into `", stringify!($field), "`."),
113            concat!(
114                "Extends `",
115                stringify!($field),
116                "` with the contents of an iterator."
117            ),
118            concat!("Sets `", stringify!($field), "`."),
119        );
120    };
121    ($field:ident, $type:ident, $func_push:ident, $func_extend:ident, $func_set:ident) => {
122        def_setter_for_vector!(packed, $field, $type, $func_push, $func_extend, $func_set);
123    };
124    (set_i, $field:ident, $type:ident, $func_push:ident, $func_extend:ident, $func_set:ident, $func_set_i: ident) => {
125        def_setter_for_vector!(packed, $field, $type, $func_push, $func_extend, $func_set);
126
127        pub fn $func_set_i(&mut self, i: usize, v: packed::$type) -> &mut Self {
128            self.$field[i] = v;
129            self
130        }
131    };
132}
133
134macro_rules! def_dedup_setter_for_vector {
135    (
136        $prefix:ident, $field:ident, $type:ident,
137        $func_push:ident, $func_extend:ident,
138        $comment_push:expr, $comment_extend:expr,
139    ) => {
140        #[doc = $comment_push]
141        pub fn $func_push(&mut self, v: $prefix::$type) -> &mut Self {
142            if !self.$field.contains(&v) {
143                self.$field.push(v);
144            }
145            self
146        }
147        #[doc = $comment_extend]
148        pub fn $func_extend<T>(&mut self, v: T) -> &mut Self
149        where
150            T: ::std::iter::IntoIterator<Item = $prefix::$type>,
151        {
152            v.into_iter().for_each(|item| {
153                if !self.$field.contains(&item) {
154                    self.$field.push(item);
155                }
156            });
157            self
158        }
159    };
160    ($prefix:ident, $field:ident, $type:ident, $func_push:ident, $func_extend:ident) => {
161        def_dedup_setter_for_vector!(
162            $prefix,
163            $field,
164            $type,
165            $func_push,
166            $func_extend,
167            concat!(
168                "Pushes an item into `",
169                stringify!($field),
170                "` only if the same item is not already in."
171            ),
172            concat!(
173                "Extends `",
174                stringify!($field),
175                "` with the contents of an iterator, skip already exist ones."
176            ),
177        );
178    };
179    ($field:ident, $type:ident, $func_push:ident, $func_extend:ident) => {
180        def_dedup_setter_for_vector!(packed, $field, $type, $func_push, $func_extend);
181    };
182}
183
184impl TransactionBuilder {
185    def_setter_simple!(version, Uint32);
186    def_setter_for_vector!(cell_deps, CellDep, cell_dep, cell_deps, set_cell_deps);
187    def_dedup_setter_for_vector!(cell_deps, CellDep, dedup_cell_dep, dedup_cell_deps);
188    def_setter_for_vector!(
189        header_deps,
190        Byte32,
191        header_dep,
192        header_deps,
193        set_header_deps
194    );
195
196    def_dedup_setter_for_vector!(header_deps, Byte32, dedup_header_dep, dedup_header_deps);
197    def_setter_for_vector!(inputs, CellInput, input, inputs, set_inputs);
198    def_setter_for_vector!(
199        set_i,
200        outputs,
201        CellOutput,
202        output,
203        outputs,
204        set_outputs,
205        set_output
206    );
207    def_setter_for_vector!(
208        set_i,
209        witnesses,
210        Bytes,
211        witness,
212        witnesses,
213        set_witnesses,
214        set_witness
215    );
216    def_setter_for_vector!(
217        set_i,
218        outputs_data,
219        Bytes,
220        output_data,
221        outputs_data,
222        set_outputs_data,
223        set_output_data
224    );
225
226    /// Converts into [`TransactionView`](struct.TransactionView.html).
227    pub fn build(self) -> core::TransactionView {
228        let Self {
229            version,
230            cell_deps,
231            header_deps,
232            inputs,
233            outputs,
234            witnesses,
235            outputs_data,
236        } = self;
237        let raw = packed::RawTransaction::new_builder()
238            .version(version)
239            .cell_deps(cell_deps.pack())
240            .header_deps(header_deps.pack())
241            .inputs(inputs.pack())
242            .outputs(outputs.pack())
243            .outputs_data(outputs_data.pack())
244            .build();
245        let tx = packed::Transaction::new_builder()
246            .raw(raw)
247            .witnesses(witnesses.pack())
248            .build();
249
250        tx.into_view()
251    }
252}