Add format traits for Work and Target
What changed, and why it matters
This commit adds new ways to print two internal numeric types (Target and Work) in binary and octal formats, and reorganizes existing hexadecimal printing code. It is a routine formatting/ergonomics improvement with no security relevance.
No security action needed; treat as normal code-quality/formatting change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch implements fmt::Binary and fmt::Octal for the internal U256 type and routes Target/Work formatting through an existing internal macro (impl_fmt_traits_for_u32_wrapper). It also adds unit tests for binary and octal formatting. There are no changes to parsing, arithmetic, serialization, consensus rules, or cryptographic logic.
Changed components
include/u256.rsunits/src/pow.rsInspect captured patch +77 / −14
diff --git a/include/u256.rs b/include/u256.rs
index fadb9412..8935c5e0 100644
--- a/include/u256.rs
+++ b/include/u256.rs
@@ -465,6 +465,52 @@ impl fmt::Debug for U256 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:#x}", self) }
}
+impl fmt::Binary for U256 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.is_zero() {
+ return f.pad_integral(true, "0b", "0");
+ }
+
+ let mut buf = [0u8; 256];
+ let mut i = 256usize;
+ let mut value = *self;
+
+ #[allow(clippy::indexing_slicing)]
+ while value > Self::ZERO {
+ i -= 1;
+ buf[i] = b'0' + (value.low_u64() & 1) as u8;
+ value = value >> 1;
+ }
+
+ let ascii_slice = buf.get(i..).expect("i <= buf.len()");
+ let s = core::str::from_utf8(ascii_slice).expect("binary digits are valid UTF8");
+ f.pad_integral(true, "0b", s)
+ }
+}
+
+impl fmt::Octal for U256 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.is_zero() {
+ return f.pad_integral(true, "0o", "0");
+ }
+
+ let mut buf = [0u8; 86];
+ let mut i = 86usize;
+ let mut value = *self;
+
+ #[allow(clippy::indexing_slicing)]
+ while value > Self::ZERO {
+ i -= 1;
+ buf[i] = b'0' + (value.low_u64() & 7) as u8;
+ value = value >> 3;
+ }
+
+ let ascii_slice = buf.get(i..).expect("i <= buf.len()");
+ let s = core::str::from_utf8(ascii_slice).expect("octal digits are valid UTF8");
+ f.pad_integral(true, "0o", s)
+ }
+}
+
/// Splits a 32 byte array into two 16 byte arrays.
fn split_in_half(a: [u8; 32]) -> ([u8; 16], [u8; 16]) {
let mut high = [0_u8; 16];
diff --git a/units/src/pow.rs b/units/src/pow.rs
index c34b7b8a..d3521f10 100644
--- a/units/src/pow.rs
+++ b/units/src/pow.rs
@@ -10,6 +10,7 @@ use arbitrary::{Arbitrary, Unstructured};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
+use crate::internal_macros::impl_fmt_traits_for_u32_wrapper;
use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
/// Implement traits and methods shared by `Target` and `Work`.
@@ -72,20 +73,6 @@ macro_rules! do_impl {
}
}
- impl fmt::LowerHex for $ty {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result {
- fmt::LowerHex::fmt(&self.0, f)
- }
- }
-
- impl fmt::UpperHex for $ty {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result {
- fmt::UpperHex::fmt(&self.0, f)
- }
- }
-
impl core::str::FromStr for $ty {
type Err = $err_ty;
@@ -129,6 +116,7 @@ impl Work {
}
do_impl!(Work, ParseWorkError);
+impl_fmt_traits_for_u32_wrapper!(Work);
impl Add for Work {
type Output = Self;
@@ -247,6 +235,7 @@ impl Target {
pub fn to_work(self) -> Work { Work(self.0.inverse()) }
}
do_impl!(Target, ParseTargetError);
+impl_fmt_traits_for_u32_wrapper!(Target);
#[rustfmt::skip] // Keep public re-exports separate.
#[cfg(feature = "encoding")]
@@ -728,6 +717,34 @@ mod tests {
check_fmt_30, 0_u32, "{:.1}", "0";
check_fmt_31, 0_u32, "{:4.1}", " 0";
check_fmt_32, 0_u32, "{:04.1}", "0000";
+
+ check_fmt_33, 0_u32, "{:b}", "0";
+ check_fmt_34, 0_u32, "{:#b}", "0b0";
+ check_fmt_35, 42_u32, "{:b}", "101010";
+ check_fmt_36, 42_u32, "{:#b}", "0b101010";
+ check_fmt_37, 42_u32, "{:8b}", " 101010";
+ check_fmt_38, 42_u32, "{:08b}", "00101010";
+ check_fmt_39, 42_u32, "{:<8b}", "101010 ";
+ check_fmt_40, 42_u32, "{:>8b}", " 101010";
+ check_fmt_41, 42_u32, "{:^8b}", " 101010 ";
+ check_fmt_42, 42_u32, "{:#10b}", " 0b101010";
+ check_fmt_43, 42_u32, "{:#010b}", "0b00101010";
+ check_fmt_44, 42_u32, "{:.4b}", "101010";
+ check_fmt_45, 42_u32, "{:10.4b}", " 101010";
+
+ check_fmt_46, 0_u32, "{:o}", "0";
+ check_fmt_47, 0_u32, "{:#o}", "0o0";
+ check_fmt_48, 42_u32, "{:o}", "52";
+ check_fmt_49, 42_u32, "{:#o}", "0o52";
+ check_fmt_50, 42_u32, "{:4o}", " 52";
+ check_fmt_51, 42_u32, "{:04o}", "0052";
+ check_fmt_52, 42_u32, "{:<4o}", "52 ";
+ check_fmt_53, 42_u32, "{:>4o}", " 52";
+ check_fmt_54, 42_u32, "{:^4o}", " 52 ";
+ check_fmt_55, 42_u32, "{:#6o}", " 0o52";
+ check_fmt_56, 42_u32, "{:#06o}", "0o0052";
+ check_fmt_57, 42_u32, "{:.4o}", "52";
+ check_fmt_58, 42_u32, "{:6.4o}", " 52";
}
#[test]
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.