Skip to content

Commit

Permalink
Truncate using even length hex string
Browse files Browse the repository at this point in the history
There are a couple of problems with the width/precision code when we
truncate:

- We are printing one too many hex characters if truncation is odd
- The nested precision code (inside width) is doing the wrong comparison

Includes unit tests to verify the behaviour of the new code.

Fix: rust-bitcoin#70
  • Loading branch information
tcharding committed Feb 21, 2024
1 parent 43752cf commit 7b21fc0
Showing 1 changed file with 26 additions and 9 deletions.
35 changes: 26 additions & 9 deletions src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ pub struct DisplayByteSlice<'a> {

impl<'a> DisplayByteSlice<'a> {
fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
use fmt::Write;
// There are at least two optimizations left:
//
// * Reusing the buffer (encoder) which may decrease the number of virtual calls
Expand All @@ -166,8 +165,14 @@ impl<'a> DisplayByteSlice<'a> {

let pad_right = if let Some(width) = f.width() {
let string_len = match f.precision() {
Some(max) if self.bytes.len() * 2 > (max + 1) / 2 => max,
Some(_) | None => self.bytes.len() * 2,
#[rustfmt::skip]
Some(max) => {
// Odd max width which makes no sense for hex strings, honour max but use even length.
let max = if max % 2 == 1 { max - 1 } else { max };
let hex_length = self.bytes.len() * 2;
if hex_length > max { max } else { hex_length }
}
None => self.bytes.len() * 2,
};

if string_len < width {
Expand Down Expand Up @@ -197,13 +202,10 @@ impl<'a> DisplayByteSlice<'a> {
};

match f.precision() {
Some(max) if self.bytes.len() > (max + 1) / 2 => {
// Do ceil division on max so as to ignore odd length max width which makes
// no sense for hex strings i.e., honour max but use even length.
Some(max) if self.bytes.len() > max / 2 => {
write!(f, "{}", self.bytes[..(max / 2)].as_hex())?;
if max % 2 == 1 && self.bytes.len() > max / 2 + 1 {
f.write_char(
case.table().byte_to_hex(self.bytes[max / 2 + 1]).as_bytes()[1].into(),
)?;
}
}
Some(_) | None => {
let mut chunks = self.bytes.chunks_exact(512);
Expand Down Expand Up @@ -442,13 +444,28 @@ mod tests {
assert_eq!(format!("{0:.4}", v.as_hex()), "1234");
}

#[test]
fn odd_precision_truncates() {
// Precision gets the most significant bytes.
let v = vec![0x12, 0x34, 0x56, 0x78];
// Remember the integer is number of hex chars not number of bytes.
assert_eq!(format!("{0:.5}", v.as_hex()), "1234");
}

#[test]
fn precision_with_padding_truncates() {
// Precision gets the most significant bytes.
let v = vec![0x12, 0x34, 0x56, 0x78];
assert_eq!(format!("{0:10.4}", v.as_hex()), "1234 ");
}

#[test]
fn odd_precision_with_padding_truncates() {
// Precision gets the most significant bytes.
let v = vec![0x12, 0x34, 0x56, 0x78];
assert_eq!(format!("{0:10.5}", v.as_hex()), "1234 ");
}

#[test]
fn precision_with_padding_pads_right() {
let v = vec![0x12, 0x34, 0x56, 0x78];
Expand Down

0 comments on commit 7b21fc0

Please sign in to comment.