Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit eafdfe1

Browse files
committed
binascii.hexlify
1 parent 5d68313 commit eafdfe1

File tree

2 files changed

+113
-11
lines changed

2 files changed

+113
-11
lines changed

Lib/test/test_binascii.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,6 @@ def test_hex(self):
258258
self.assertEqual(binascii.hexlify(self.type2test(s)), t)
259259
self.assertEqual(binascii.unhexlify(self.type2test(t)), u)
260260

261-
# TODO: RUSTPYTHON
262-
@unittest.expectedFailure
263261
def test_hex_separator(self):
264262
"""Test that hexlify and b2a_hex are binary versions of bytes.hex."""
265263
# Logic of separators is tested in test_bytes.py. This checks that
@@ -388,8 +386,6 @@ def test_empty_string(self):
388386
except Exception as err:
389387
self.fail("{}({!r}) raises {!r}".format(func, empty, err))
390388

391-
# TODO: RUSTPYTHON
392-
@unittest.expectedFailure
393389
def test_unicode_b2a(self):
394390
# Unicode strings are not accepted by b2a_* functions.
395391
for func in set(all_functions) - set(a2b_functions):

stdlib/src/binascii.rs

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,120 @@ mod decl {
4343

4444
#[pyfunction(name = "b2a_hex")]
4545
#[pyfunction]
46-
fn hexlify(data: ArgBytesLike) -> Vec<u8> {
46+
fn hexlify(
47+
data: ArgBytesLike,
48+
sep: OptionalArg<ArgAsciiBuffer>,
49+
bytes_per_sep: OptionalArg<isize>,
50+
vm: &VirtualMachine,
51+
) -> PyResult<Vec<u8>> {
52+
let bytes_per_sep = bytes_per_sep.unwrap_or(1);
53+
4754
data.with_ref(|bytes| {
48-
let mut hex = Vec::<u8>::with_capacity(bytes.len() * 2);
49-
for b in bytes {
50-
hex.push(hex_nibble(b >> 4));
51-
hex.push(hex_nibble(b & 0xf));
55+
// Get separator character if provided
56+
let sep_char = if let OptionalArg::Present(sep_buf) = sep {
57+
sep_buf.with_ref(|sep_bytes| {
58+
if sep_bytes.len() != 1 {
59+
return Err(vm.new_value_error("sep must be length 1.".to_owned()));
60+
}
61+
let sep_char = sep_bytes[0];
62+
if !sep_char.is_ascii() {
63+
return Err(vm.new_value_error("sep must be ASCII.".to_owned()));
64+
}
65+
Ok(Some(sep_char))
66+
})?
67+
} else {
68+
None
69+
};
70+
71+
// If no separator or bytes_per_sep is 0, use simple hexlify
72+
if sep_char.is_none() || bytes_per_sep == 0 || bytes.is_empty() {
73+
let mut hex = Vec::<u8>::with_capacity(bytes.len() * 2);
74+
for b in bytes {
75+
hex.push(hex_nibble(b >> 4));
76+
hex.push(hex_nibble(b & 0xf));
77+
}
78+
return Ok(hex);
79+
}
80+
81+
let sep_char = sep_char.unwrap();
82+
let abs_bytes_per_sep = bytes_per_sep.unsigned_abs();
83+
84+
// If separator interval is >= data length, no separators needed
85+
if abs_bytes_per_sep >= bytes.len() {
86+
let mut hex = Vec::<u8>::with_capacity(bytes.len() * 2);
87+
for b in bytes {
88+
hex.push(hex_nibble(b >> 4));
89+
hex.push(hex_nibble(b & 0xf));
90+
}
91+
return Ok(hex);
92+
}
93+
94+
// Calculate result length
95+
let num_separators = (bytes.len() - 1) / abs_bytes_per_sep;
96+
let result_len = bytes.len() * 2 + num_separators;
97+
let mut hex = vec![0u8; result_len];
98+
99+
if bytes_per_sep < 0 {
100+
// Left-to-right processing (negative bytes_per_sep)
101+
let mut i = 0; // input index
102+
let mut j = 0; // output index
103+
let chunks = bytes.len() / abs_bytes_per_sep;
104+
105+
// Process complete chunks
106+
for _ in 0..chunks {
107+
for _ in 0..abs_bytes_per_sep {
108+
let b = bytes[i];
109+
hex[j] = hex_nibble(b >> 4);
110+
hex[j + 1] = hex_nibble(b & 0xf);
111+
i += 1;
112+
j += 2;
113+
}
114+
if i < bytes.len() {
115+
hex[j] = sep_char;
116+
j += 1;
117+
}
118+
}
119+
120+
// Process remaining bytes
121+
while i < bytes.len() {
122+
let b = bytes[i];
123+
hex[j] = hex_nibble(b >> 4);
124+
hex[j + 1] = hex_nibble(b & 0xf);
125+
i += 1;
126+
j += 2;
127+
}
128+
} else {
129+
// Right-to-left processing (positive bytes_per_sep)
130+
let mut i = bytes.len() as isize - 1; // input index
131+
let mut j = result_len as isize - 1; // output index
132+
let chunks = bytes.len() / abs_bytes_per_sep;
133+
134+
// Process complete chunks from right
135+
for _ in 0..chunks {
136+
for _ in 0..abs_bytes_per_sep {
137+
let b = bytes[i as usize];
138+
hex[j as usize] = hex_nibble(b & 0xf);
139+
hex[(j - 1) as usize] = hex_nibble(b >> 4);
140+
i -= 1;
141+
j -= 2;
142+
}
143+
if i >= 0 {
144+
hex[j as usize] = sep_char;
145+
j -= 1;
146+
}
147+
}
148+
149+
// Process remaining bytes
150+
while i >= 0 {
151+
let b = bytes[i as usize];
152+
hex[j as usize] = hex_nibble(b & 0xf);
153+
hex[(j - 1) as usize] = hex_nibble(b >> 4);
154+
i -= 1;
155+
j -= 2;
156+
}
52157
}
53-
hex
158+
159+
Ok(hex)
54160
})
55161
}
56162

@@ -368,7 +474,7 @@ mod decl {
368474
#[derive(FromArgs)]
369475
struct B2aQpArgs {
370476
#[pyarg(any)]
371-
data: ArgAsciiBuffer,
477+
data: ArgBytesLike,
372478
#[pyarg(named, default = false)]
373479
quotetabs: bool,
374480
#[pyarg(named, default = true)]

0 commit comments

Comments
 (0)