Manually implement Debug on Witness

The current derived debug implementation on `Witness` prints the content
field as an array of integers. We can do better than this by manually
implementing `Debug`.

With this applied `Witness` is printed as follows: (first line is `{:?}`
and the next is `{:#?}`):

Using `{:?}`:
```
Witness: { indices: 3, indices_start: 8, witnesses: [[0x00], [0x02, 0x03], [0x04, 0x05]] }
```

Using `{:#?}`:
```
Witness: {
    indices: 3,
    indices_start: 8,
    witnesses: [
        [0x00],
        [0x02, 0x03],
        [0x04, 0x05],
     ],
}
```
This commit is contained in:
Tobin C. Harding 2023-06-20 10:22:48 +10:00
parent 1318ff88e5
commit d45dbef3e7
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
1 changed files with 104 additions and 1 deletions

View File

@ -6,6 +6,7 @@
//! //!
use core::convert::TryInto; use core::convert::TryInto;
use core::fmt;
use core::ops::Index; use core::ops::Index;
use secp256k1::ecdsa; use secp256k1::ecdsa;
@ -28,7 +29,7 @@ use crate::{Script, VarInt};
/// saving some allocations. /// saving some allocations.
/// ///
/// [segwit upgrade]: <https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki> /// [segwit upgrade]: <https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki>
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Witness { pub struct Witness {
/// Contains the witness `Vec<Vec<u8>>` serialization without the initial varint indicating the /// Contains the witness `Vec<Vec<u8>>` serialization without the initial varint indicating the
/// number of elements (which is stored in `witness_elements`). /// number of elements (which is stored in `witness_elements`).
@ -45,6 +46,108 @@ pub struct Witness {
indices_start: usize, indices_start: usize,
} }
impl fmt::Debug for Witness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
if f.alternate() {
fmt_debug_pretty(self, f)
} else {
fmt_debug(self, f)
}
}
}
fn fmt_debug(w: &Witness, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
#[rustfmt::skip]
let comma_or_close = |current_index, last_index| {
if current_index == last_index { "]" } else { ", " }
};
f.write_str("Witness: { ")?;
f.write_str(&indices_str(w))?;
f.write_str(&indices_start_str(w))?;
f.write_str("witnesses: [")?;
let instructions = w.iter();
let last_instruction = instructions.len() - 1;
for (i, instruction) in instructions.enumerate() {
let bytes = instruction.iter();
let last_byte = bytes.len() - 1;
f.write_str("[")?;
for (j, byte) in bytes.enumerate() {
f.write_str(&byte_str(*byte))?;
f.write_str(comma_or_close(j, last_byte))?;
}
f.write_str(comma_or_close(i, last_instruction))?;
}
f.write_str(" }")?;
Ok(())
}
fn fmt_debug_pretty(w: &Witness, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let mut indent = 0;
writeln(f, indent, "Witness: { ")?;
indent += 1;
writeln(f, indent, &indices_str(w))?;
writeln(f, indent, &indices_start_str(w))?;
writeln(f, indent, "witnesses: [ ")?;
indent += 1;
let instructions = w.iter();
for instruction in instructions {
let bytes = instruction.iter();
let last_byte = bytes.len() - 1;
write(f, indent, "[")?;
for (j, byte) in bytes.enumerate() {
f.write_str(&byte_str(*byte))?;
if j == last_byte {
f.write_str("],\n")?;
} else {
f.write_str(", ")?;
}
}
}
indent -= 1;
writeln(f, indent, "],")?;
indent -= 1;
write(f, indent, "}")?;
Ok(())
}
fn indices_str(w: &Witness) -> String { format!("indices: {}, ", w.witness_elements) }
fn indices_start_str(w: &Witness) -> String { format!("indices_start: {}, ", w.indices_start) }
fn byte_str(byte: u8) -> String { format!("{:#04x}", byte) }
fn writeln(f: &mut fmt::Formatter<'_>, indent: usize, s: &str) -> Result<(), fmt::Error> {
write(f, indent, s)?;
f.write_str("\n")
}
fn write(f: &mut fmt::Formatter<'_>, indent: usize, s: &str) -> Result<(), fmt::Error> {
for _ in 0..indent {
f.write_str(" ")?;
}
f.write_str(s)
}
/// An iterator returning individual witness elements. /// An iterator returning individual witness elements.
pub struct Iter<'a> { pub struct Iter<'a> {
inner: &'a [u8], inner: &'a [u8],