@@ -43,14 +43,120 @@ mod decl {
43
43
44
44
#[ pyfunction( name = "b2a_hex" ) ]
45
45
#[ 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
+
47
54
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
+ }
52
157
}
53
- hex
158
+
159
+ Ok ( hex)
54
160
} )
55
161
}
56
162
@@ -368,7 +474,7 @@ mod decl {
368
474
#[ derive( FromArgs ) ]
369
475
struct B2aQpArgs {
370
476
#[ pyarg( any) ]
371
- data : ArgAsciiBuffer ,
477
+ data : ArgBytesLike ,
372
478
#[ pyarg( named, default = false ) ]
373
479
quotetabs : bool ,
374
480
#[ pyarg( named, default = true ) ]
0 commit comments