Skip to content

Commit 94625e7

Browse files
committed
segwit: Add a buffer when writing
Currently we call `fmt::Write::write_char` and `io::Write::write_all` in a loop while iterating over the encoded characters of a bech32 string. This is inefficient. Add a buffer and copy ASCII bytes into it while looping the write the whole buffer out in a single call. The buffer has a size of 90 bytes because we know the bech32 string is guaranteed to be 90 chars or less.
1 parent 596f1f7 commit 94625e7

File tree

1 file changed

+64
-24
lines changed

1 file changed

+64
-24
lines changed

src/segwit.rs

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -156,19 +156,30 @@ pub fn encode_lower_to_fmt_unchecked<W: fmt::Write>(
156156
witness_version: Fe32,
157157
witness_program: &[u8],
158158
) -> fmt::Result {
159+
let mut buf = [0u8; MAX_STRING_LENGTH];
160+
let mut pos = 0;
161+
159162
let iter = witness_program.iter().copied().bytes_to_fes();
160163
match witness_version {
161164
VERSION_0 => {
162-
for c in iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).chars() {
163-
fmt.write_char(c)?;
164-
}
165+
let bytes = iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).bytes();
166+
buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
167+
*dst = src;
168+
pos += 1;
169+
});
165170
}
166171
version => {
167-
for c in iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).chars() {
168-
fmt.write_char(c)?;
169-
}
172+
let bytes = iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).bytes();
173+
buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
174+
*dst = src;
175+
pos += 1;
176+
});
170177
}
171178
}
179+
180+
let s = core::str::from_utf8(&buf[..pos]).expect("we only write ASCII");
181+
fmt.write_str(s)?;
182+
172183
Ok(())
173184
}
174185

@@ -185,20 +196,30 @@ pub fn encode_upper_to_fmt_unchecked<W: fmt::Write>(
185196
witness_version: Fe32,
186197
witness_program: &[u8],
187198
) -> fmt::Result {
199+
let mut buf = [0u8; MAX_STRING_LENGTH];
200+
let mut pos = 0;
201+
188202
let iter = witness_program.iter().copied().bytes_to_fes();
189203
match witness_version {
190204
VERSION_0 => {
191-
for c in iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).chars() {
192-
fmt.write_char(c.to_ascii_uppercase())?;
193-
}
205+
let bytes = iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).bytes();
206+
buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
207+
*dst = src.to_ascii_uppercase();
208+
pos += 1;
209+
});
194210
}
195211
version => {
196-
for c in iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).chars() {
197-
fmt.write_char(c.to_ascii_uppercase())?;
198-
}
212+
let bytes = iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).bytes();
213+
buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
214+
*dst = src.to_ascii_uppercase();
215+
pos += 1;
216+
});
199217
}
200218
}
201219

220+
let s = core::str::from_utf8(&buf[..pos]).expect("we only write ASCII");
221+
fmt.write_str(s)?;
222+
202223
Ok(())
203224
}
204225

@@ -229,19 +250,29 @@ pub fn encode_lower_to_writer_unchecked<W: std::io::Write>(
229250
witness_version: Fe32,
230251
witness_program: &[u8],
231252
) -> std::io::Result<()> {
253+
let mut buf = [0u8; MAX_STRING_LENGTH];
254+
let mut pos = 0;
255+
232256
let iter = witness_program.iter().copied().bytes_to_fes();
233257
match witness_version {
234258
VERSION_0 => {
235-
for c in iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).chars() {
236-
w.write_all(&[c.to_ascii_lowercase() as u8])?;
237-
}
259+
let bytes = iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).bytes();
260+
buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
261+
*dst = src;
262+
pos += 1;
263+
});
238264
}
239265
version => {
240-
for c in iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).chars() {
241-
w.write_all(&[c.to_ascii_lowercase() as u8])?;
242-
}
266+
let bytes = iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).bytes();
267+
buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
268+
*dst = src;
269+
pos += 1;
270+
});
243271
}
244272
}
273+
274+
w.write_all(&buf[..pos])?;
275+
245276
Ok(())
246277
}
247278

@@ -259,20 +290,29 @@ pub fn encode_upper_to_writer_unchecked<W: std::io::Write>(
259290
witness_version: Fe32,
260291
witness_program: &[u8],
261292
) -> std::io::Result<()> {
293+
let mut buf = [0u8; MAX_STRING_LENGTH];
294+
let mut pos = 0;
295+
262296
let iter = witness_program.iter().copied().bytes_to_fes();
263297
match witness_version {
264298
VERSION_0 => {
265-
for c in iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).chars() {
266-
w.write_all(&[c.to_ascii_uppercase() as u8])?;
267-
}
299+
let bytes = iter.with_checksum::<Bech32>(&hrp).with_witness_version(VERSION_0).bytes();
300+
buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
301+
*dst = src.to_ascii_uppercase();
302+
pos += 1;
303+
});
268304
}
269305
version => {
270-
for c in iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).chars() {
271-
w.write_all(&[c.to_ascii_uppercase() as u8])?;
272-
}
306+
let bytes = iter.with_checksum::<Bech32m>(&hrp).with_witness_version(version).bytes();
307+
buf.iter_mut().zip(bytes).for_each(|(dst, src)| {
308+
*dst = src.to_ascii_uppercase();
309+
pos += 1;
310+
});
273311
}
274312
}
275313

314+
w.write_all(&buf[..pos])?;
315+
276316
Ok(())
277317
}
278318

0 commit comments

Comments
 (0)