12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
- use core:: fmt:: Write ;
16
- use util:: c_types:: { c_char, c_uchar} ;
15
+ use util:: c_types:: c_uchar;
17
16
18
17
/// Zero a buffer using volatile writes. Accepts null-ptr and 0-length buffers and does nothing.
19
18
///
@@ -31,19 +30,17 @@ pub extern "C" fn rust_util_zero(mut dst: BytesMut) {
31
30
/// * `buf` - bytes to convert to hex.
32
31
/// * `out` - hex will be written here. out len must be at least 2*buf.len+1.
33
32
#[ no_mangle]
34
- pub extern "C" fn rust_util_uint8_to_hex ( buf : Bytes , mut out : CStrMut ) {
35
- let min_len = buf. len * 2 ;
36
- match out. write ( min_len, |out| {
37
- // Avoid .unwrap() here until the following compiler regression is fixed:
38
- // https://github.com/rust-lang/rust/issues/83925
39
- match hex:: encode_to_slice ( & buf, out) {
40
- Ok ( ( ) ) => { }
41
- Err ( err) => panic ! ( "{:?}" , err) ,
42
- }
43
- } ) {
33
+ pub extern "C" fn rust_util_uint8_to_hex ( buf : Bytes , mut out : BytesMut ) {
34
+ let bytes = buf. as_ref ( ) ;
35
+ let hexlen = bytes. len ( ) * 2 ;
36
+ // Avoid .unwrap() here until the following compiler regression is fixed:
37
+ // https://github.com/rust-lang/rust/issues/83925
38
+ match hex:: encode_to_slice ( bytes, & mut out. as_mut ( ) [ ..hexlen] ) {
44
39
Ok ( ( ) ) => { }
45
- Err ( _ ) => panic ! ( "couldn't write to buffer" ) ,
40
+ Err ( err ) => panic ! ( "{:?}" , err ) ,
46
41
}
42
+ // Null terminator.
43
+ out. as_mut ( ) [ hexlen] = 0 ;
47
44
}
48
45
49
46
#[ repr( C ) ]
@@ -100,99 +97,6 @@ impl AsMut<[u8]> for BytesMut {
100
97
}
101
98
}
102
99
103
- /// CStrMut is a "growable" container which keeps track of some array allocated by C with a length
104
- /// and a capacity state. It always contains a null-terminated string. The string (excluding null
105
- /// terminator) can therefore be maximally `capacity-1` long.
106
- #[ repr( C ) ]
107
- pub struct CStrMut {
108
- buf : * mut c_char ,
109
- len : usize ,
110
- cap : usize ,
111
- }
112
-
113
- impl CStrMut {
114
- /// Create a new growable string with capacity `cap`. Only allowed for non-null pointers with
115
- /// length or null pointers with 0 length due to limitation in `core::slice`. Unsafe because it
116
- /// will read until it finds a null character.
117
- pub unsafe fn new ( buf : * mut c_char , cap : usize ) -> Self {
118
- let mut len = 0 ;
119
- let mut buf = buf;
120
- if buf. is_null ( ) {
121
- if cap != 0 {
122
- panic ! ( "Null pointer can't have capacity" ) ;
123
- }
124
- buf = core:: ptr:: NonNull :: dangling ( ) . as_ptr ( ) ;
125
- } else {
126
- let mut b = buf;
127
- while b. read ( ) != 0 {
128
- len += 1 ;
129
- b = b. offset ( 1 ) ;
130
- if len == cap {
131
- panic ! ( "CStrMut not null terminated" ) ;
132
- }
133
- }
134
- }
135
-
136
- CStrMut { buf, len, cap }
137
- }
138
-
139
- /// Provide a mutable slice to an unused range of the buffer. The provided function `f` must
140
- /// fill the requested buffer with utf-8 valid characters and it must not write a null
141
- /// character in the buffer.
142
- ///
143
- /// # Panics
144
- ///
145
- /// This function returns an error in case the provided buffer contains NULL or non-valid utf-8
146
- /// characters after function `f` is applied. It will also return an error if more bytes are
147
- /// requested then are available.
148
- pub fn write < F > ( & mut self , req : usize , f : F ) -> Result < ( ) , core:: fmt:: Error >
149
- where
150
- F : FnOnce ( & mut [ u8 ] ) ,
151
- {
152
- // Must be room for requested amount of bytes and null terminator.
153
- if self . cap - self . len < req + 1 {
154
- // Not enough bytes left in buffer
155
- return Err ( core:: fmt:: Error ) ;
156
- }
157
- let len = self . len ;
158
- let slice = unsafe { self . as_bytes_mut ( ) } ;
159
- let slice = & mut slice[ len..len + req + 1 ] ;
160
- let write_slice = & mut slice[ 0 ..req] ;
161
- f ( write_slice) ;
162
- if write_slice. iter ( ) . any ( |& c| c == 0 ) {
163
- // null terminated strings can't contain null
164
- return Err ( core:: fmt:: Error ) ;
165
- }
166
- if core:: str:: from_utf8 ( write_slice) . is_err ( ) {
167
- // strings must be valid utf-8
168
- return Err ( core:: fmt:: Error ) ;
169
- }
170
- slice[ req] = 0 ;
171
- self . len += req;
172
- Ok ( ( ) )
173
- }
174
-
175
- /// Get slice of underlying byte array. Unsafe because you have to ensure that length is up to
176
- /// date and that there is a null character at `buf[len]`.
177
- pub unsafe fn as_bytes_mut ( & mut self ) -> & mut [ u8 ] {
178
- core:: slice:: from_raw_parts_mut ( self . buf , self . cap )
179
- }
180
- }
181
-
182
- impl AsRef < str > for CStrMut {
183
- fn as_ref ( & self ) -> & str {
184
- unsafe { core:: str:: from_utf8_unchecked ( core:: slice:: from_raw_parts ( self . buf , self . len ) ) }
185
- }
186
- }
187
-
188
- impl core:: fmt:: Write for CStrMut {
189
- fn write_str ( & mut self , s : & str ) -> Result < ( ) , core:: fmt:: Error > {
190
- self . write ( s. len ( ) , |buf| {
191
- buf. copy_from_slice ( s. as_bytes ( ) ) ;
192
- } )
193
- }
194
- }
195
-
196
100
/// Convert buffer to slice
197
101
///
198
102
/// * `buf` - Must be a valid pointer to an array of bytes
@@ -211,29 +115,20 @@ pub unsafe extern "C" fn rust_util_bytes_mut(buf: *mut c_uchar, len: usize) -> B
211
115
BytesMut { buf, len }
212
116
}
213
117
214
- /// Convert buffer to mutable str. The whole buffer is considered empty from start.
215
- ///
216
- /// * `buf` - Must be a valid pointer to an array of bytes
217
- /// * `cap` - Length of buffer, `buf_ptr[cap-1]` must be a valid dereference
218
- #[ no_mangle]
219
- pub unsafe extern "C" fn rust_util_cstr_mut ( buf : * mut c_char , cap : usize ) -> CStrMut {
220
- if !buf. is_null ( ) {
221
- buf. write ( 0 ) ;
222
- }
223
- CStrMut :: new ( buf, cap)
224
- }
225
-
226
118
/// Base58Check-encode the input.
227
119
///
228
120
/// #Safety
229
121
/// buf and out must not be NULL and point to valid memory areas.
230
122
#[ no_mangle]
231
- pub unsafe extern "C" fn rust_base58_encode_check ( buf : Bytes , mut out : CStrMut ) -> bool {
123
+ pub unsafe extern "C" fn rust_base58_encode_check ( buf : Bytes , mut out : BytesMut ) -> bool {
232
124
if buf. len == 0 {
233
125
return false ;
234
126
}
235
127
let encoded = bs58:: encode ( buf. as_ref ( ) ) . with_check ( ) . into_string ( ) ;
236
- write ! ( & mut out, "{}" , encoded) . is_ok ( )
128
+ out. as_mut ( ) [ ..encoded. len ( ) ] . copy_from_slice ( encoded. as_bytes ( ) ) ;
129
+ // Null-terminator.
130
+ out. as_mut ( ) [ encoded. len ( ) ] = 0 ;
131
+ true
237
132
}
238
133
239
134
#[ cfg( test) ]
@@ -276,80 +171,18 @@ mod tests {
276
171
}
277
172
278
173
#[ test]
279
- fn test_cstr_mut ( ) {
280
- let mut start = String :: from ( "foo\0 bar" ) ;
281
- let mut cstr_mut = unsafe { rust_util_cstr_mut ( start. as_mut_ptr ( ) , start. len ( ) ) } ;
282
- assert_eq ! ( cstr_mut. len, 0 ) ;
283
- assert_eq ! ( cstr_mut. as_ref( ) , "" ) ;
284
- cstr_mut. write ( 1 , |buf| buf[ 0 ] = b'g' ) . unwrap ( ) ;
285
- assert_eq ! ( cstr_mut. as_ref( ) , "g" ) ;
286
- }
287
-
288
- #[ test]
289
- fn test_cstr_mut_new ( ) {
290
- let mut start = String :: from ( "foo\0 bar" ) ;
291
- let mut cstr_mut = unsafe { CStrMut :: new ( start. as_mut_ptr ( ) , start. len ( ) ) } ;
292
- assert_eq ! ( cstr_mut. len, 3 ) ;
293
- assert_eq ! ( cstr_mut. as_ref( ) , "foo" ) ;
294
- cstr_mut. write ( 1 , |buf| buf[ 0 ] = b'g' ) . unwrap ( ) ;
295
- assert_eq ! ( cstr_mut. as_ref( ) , "foog" ) ;
296
- }
297
-
298
- #[ test]
299
- #[ should_panic]
300
- fn test_invalid_cstr_mut ( ) {
301
- let mut buf = [ 1 , 2 , 3 ] ;
302
- let cstr_mut = unsafe { CStrMut :: new ( buf. as_mut_ptr ( ) , buf. len ( ) ) } ;
303
- // panics as there is no null terminator.
304
- cstr_mut. as_ref ( ) ;
305
- }
306
-
307
- #[ test]
308
- fn test_invalid_cstr_mut_write_null ( ) {
309
- let mut s = String :: from ( "abc\0 xxx" ) ;
310
- let mut cstr_mut = unsafe { CStrMut :: new ( s. as_mut_ptr ( ) , s. len ( ) ) } ;
311
- assert ! ( cstr_mut. write( 1 , |buf| buf[ 0 ] = 0 ) . is_err( ) ) ;
312
- }
313
-
314
- #[ test]
315
- fn test_invalid_cstr_mut_out_of_buffer ( ) {
316
- let mut s = String :: from ( "abc\0 " ) ;
317
- let mut cstr_mut = unsafe { CStrMut :: new ( s. as_mut_ptr ( ) , s. len ( ) ) } ;
318
- assert ! ( cstr_mut. write( 1 , |buf| buf[ 0 ] = b'd' ) . is_err( ) ) ;
319
- }
320
-
321
- #[ test]
322
- fn test_cstr_mut_write ( ) {
323
- let mut buf = vec ! [ 0 ; 9 ] ;
324
- let mut cstr_mut = unsafe { CStrMut :: new ( buf. as_mut_ptr ( ) , buf. len ( ) ) } ;
325
- use std:: fmt:: Write ;
326
- assert ! ( write!( & mut cstr_mut, "test" ) . is_ok( ) ) ;
327
- assert ! ( buf. starts_with( b"test\0 " ) ) ;
328
- assert ! ( write!( & mut cstr_mut, " foo" ) . is_ok( ) ) ;
329
- assert ! ( buf. starts_with( b"test foo\0 " ) ) ;
330
- }
331
-
332
- #[ test]
333
- fn test_cstr_mut_write_too_much ( ) {
334
- let mut buf = vec ! [ 0 ; 9 ] ;
335
- let mut cstr_mut = unsafe { CStrMut :: new ( buf. as_mut_ptr ( ) , buf. len ( ) ) } ;
336
- use std:: fmt:: Write ;
337
- assert ! ( write!( & mut cstr_mut, "test foo " ) . is_err( ) ) ;
338
- }
339
-
340
- #[ test]
341
- fn u8_to_hexing ( ) {
342
- let buf = [ 1u8 , 2 , 3 , 14 , 15 , 255 , 1 ] ;
343
- let mut string = String :: from ( "\0 xxxxxxxxxxxxx" ) ;
344
- rust_util_uint8_to_hex ( rust_util_bytes ( buf. as_ptr ( ) , buf. len ( ) - 1 ) , unsafe {
345
- rust_util_cstr_mut ( string. as_mut_ptr ( ) , string. len ( ) - 1 )
174
+ fn test_uint8_to_hex ( ) {
175
+ let buf = [ 1u8 , 2 , 3 , 14 , 15 , 255 ] ;
176
+ let mut string = String :: from ( "xxxxxxxxxxxxx" ) ;
177
+ rust_util_uint8_to_hex ( rust_util_bytes ( buf. as_ptr ( ) , buf. len ( ) ) , unsafe {
178
+ rust_util_bytes_mut ( string. as_mut_ptr ( ) , string. len ( ) )
346
179
} ) ;
347
- assert_eq ! ( string, "0102030e0fff\0 x " ) ;
180
+ assert_eq ! ( string, "0102030e0fff\0 " ) ;
348
181
349
182
// Bigger buffer also works.
350
183
let mut string = String :: from ( "\0 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ) ;
351
- rust_util_uint8_to_hex ( rust_util_bytes ( buf. as_ptr ( ) , buf. len ( ) - 1 ) , unsafe {
352
- rust_util_cstr_mut ( string. as_mut_ptr ( ) , string. len ( ) )
184
+ rust_util_uint8_to_hex ( rust_util_bytes ( buf. as_ptr ( ) , buf. len ( ) ) , unsafe {
185
+ rust_util_bytes_mut ( string. as_mut_ptr ( ) , string. len ( ) )
353
186
} ) ;
354
187
assert_eq ! ( string, "0102030e0fff\0 xxxxxxxxxxxxxxxxxxxxxxx" ) ;
355
188
}
@@ -361,12 +194,10 @@ mod tests {
361
194
assert ! ( unsafe {
362
195
rust_base58_encode_check(
363
196
rust_util_bytes( buf. as_ptr( ) , buf. len( ) ) ,
364
- rust_util_cstr_mut ( result_buf. as_mut_ptr( ) , result_buf. len( ) ) ,
197
+ rust_util_bytes_mut ( result_buf. as_mut_ptr( ) , result_buf. len( ) ) ,
365
198
)
366
199
} ) ;
367
- assert_eq ! (
368
- ( unsafe { rust_util_cstr( result_buf. as_ptr( ) ) } ) . as_ref( ) ,
369
- "LUC1eAJa5jW"
370
- ) ;
200
+ let expected = b"LUC1eAJa5jW\0 " ;
201
+ assert_eq ! ( & result_buf[ ..expected. len( ) ] , expected) ;
371
202
}
372
203
}
0 commit comments