Skip to content

Commit ad3bc41

Browse files
authored
feat(cast): new pad cmd for hex data (#11152)
* chore(cast): add `--left` flag to cmd `to-bytes32` * revert and create new `pad` cmd * make left-pad default
1 parent a4c0904 commit ad3bc41

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

crates/cast/src/args.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ pub async fn run_command(args: CastArgs) -> Result<()> {
165165
let value = stdin::unwrap_line(bytes)?;
166166
sh_println!("{}", SimpleCast::to_bytes32(&value)?)?
167167
}
168+
CastSubcommand::Pad { data, right, left: _, len } => {
169+
let value = stdin::unwrap_line(data)?;
170+
sh_println!("{}", SimpleCast::pad(&value, right, len)?)?
171+
}
168172
CastSubcommand::FormatBytes32String { string } => {
169173
let value = stdin::unwrap_line(string)?;
170174
sh_println!("{}", SimpleCast::format_bytes32_string(&value)?)?

crates/cast/src/lib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,48 @@ impl SimpleCast {
16341634
Ok(hex::encode_prefixed(bytes32))
16351635
}
16361636

1637+
/// Pads hex data to a specified length
1638+
///
1639+
/// # Example
1640+
///
1641+
/// ```
1642+
/// use cast::SimpleCast as Cast;
1643+
///
1644+
/// let padded = Cast::pad("abcd", true, 20)?;
1645+
/// assert_eq!(padded, "0xabcd000000000000000000000000000000000000");
1646+
///
1647+
/// let padded = Cast::pad("abcd", false, 20)?;
1648+
/// assert_eq!(padded, "0x000000000000000000000000000000000000abcd");
1649+
///
1650+
/// let padded = Cast::pad("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", true, 32)?;
1651+
/// assert_eq!(padded, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2000000000000000000000000");
1652+
///
1653+
/// let padded = Cast::pad("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", false, 32)?;
1654+
/// assert_eq!(padded, "0x000000000000000000000000C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
1655+
///
1656+
/// let err = Cast::pad("1234", false, 1).unwrap_err();
1657+
/// assert_eq!(err.to_string(), "input length exceeds target length");
1658+
///
1659+
/// let err = Cast::pad("foobar", false, 32).unwrap_err();
1660+
/// assert_eq!(err.to_string(), "input is not a valid hex");
1661+
///
1662+
/// # Ok::<_, eyre::Report>(())
1663+
/// ```
1664+
pub fn pad(s: &str, right: bool, len: usize) -> Result<String> {
1665+
let s = strip_0x(s);
1666+
let hex_len = len * 2;
1667+
1668+
// Validate input
1669+
if s.len() > hex_len {
1670+
eyre::bail!("input length exceeds target length");
1671+
}
1672+
if !s.chars().all(|c| c.is_ascii_hexdigit()) {
1673+
eyre::bail!("input is not a valid hex");
1674+
}
1675+
1676+
Ok(if right { format!("0x{s:0<hex_len$}") } else { format!("0x{s:0>hex_len$}") })
1677+
}
1678+
16371679
/// Decodes string from bytes32 value
16381680
pub fn parse_bytes32_string(s: &str) -> Result<String> {
16391681
let bytes = hex::decode(s)?;

crates/cast/src/opts.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,25 @@ pub enum CastSubcommand {
151151
bytes: Option<String>,
152152
},
153153

154+
/// Pads hex data to a specified length.
155+
#[command(visible_aliases = &["pd"])]
156+
Pad {
157+
/// The hex data to pad.
158+
data: Option<String>,
159+
160+
/// Right-pad the data (instead of left-pad).
161+
#[arg(long)]
162+
right: bool,
163+
164+
/// Left-pad the data (default).
165+
#[arg(long, conflicts_with = "right")]
166+
left: bool,
167+
168+
/// Target length in bytes (default: 32).
169+
#[arg(long, default_value = "32")]
170+
len: usize,
171+
},
172+
154173
/// Convert an integer into a fixed point number.
155174
#[command(visible_aliases = &["--to-fix", "tf", "2f"])]
156175
ToFixedPoint {

0 commit comments

Comments
 (0)