1use ckb_types::{constants, core, packed, prelude::*};
2use derive_getters::Getters;
3
4#[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
28impl ::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 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}