1
1
use super :: chars:: { Char16 , Char8 , NUL_16 , NUL_8 } ;
2
+ use super :: UnalignedSlice ;
2
3
use core:: fmt;
3
4
use core:: iter:: Iterator ;
4
- use core:: marker:: PhantomData ;
5
5
use core:: mem:: MaybeUninit ;
6
6
use core:: result:: Result ;
7
7
use core:: slice;
8
+
8
9
#[ cfg( feature = "exts" ) ]
9
- use { super :: CString16 , crate :: alloc_api :: vec :: Vec } ;
10
+ use super :: CString16 ;
10
11
11
12
/// Errors which can occur during checked `[uN]` -> `CStrN` conversions
12
13
#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
@@ -21,7 +22,7 @@ pub enum FromSliceWithNulError {
21
22
NotNulTerminated ,
22
23
}
23
24
24
- /// Error returned by [`UnalignedCStr16::to_cstr16 `].
25
+ /// Error returned by [`CStr16::from_unaligned_slice `].
25
26
#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
26
27
pub enum UnalignedCStr16Error {
27
28
/// An invalid character was encountered.
@@ -261,6 +262,31 @@ impl CStr16 {
261
262
} )
262
263
}
263
264
265
+ /// Create a [`CStr16`] from an [`UnalignedSlice`] using an aligned
266
+ /// buffer for storage. The lifetime of the output is tied to `buf`,
267
+ /// not `src`.
268
+ pub fn from_unaligned_slice < ' buf > (
269
+ src : & UnalignedSlice < ' _ , u16 > ,
270
+ buf : & ' buf mut [ MaybeUninit < u16 > ] ,
271
+ ) -> Result < & ' buf CStr16 , UnalignedCStr16Error > {
272
+ // The input `buf` might be longer than needed, so get a
273
+ // subslice of the required length.
274
+ let buf = buf
275
+ . get_mut ( ..src. len ( ) )
276
+ . ok_or ( UnalignedCStr16Error :: BufferTooSmall ) ?;
277
+
278
+ src. copy_to_maybe_uninit ( buf) ;
279
+ let buf = unsafe {
280
+ // Safety: `copy_buf` fully initializes the slice.
281
+ MaybeUninit :: slice_assume_init_ref ( buf)
282
+ } ;
283
+ CStr16 :: from_u16_with_nul ( buf) . map_err ( |e| match e {
284
+ FromSliceWithNulError :: InvalidChar ( v) => UnalignedCStr16Error :: InvalidChar ( v) ,
285
+ FromSliceWithNulError :: InteriorNul ( v) => UnalignedCStr16Error :: InteriorNul ( v) ,
286
+ FromSliceWithNulError :: NotNulTerminated => UnalignedCStr16Error :: NotNulTerminated ,
287
+ } )
288
+ }
289
+
264
290
/// Returns the inner pointer to this C string
265
291
pub fn as_ptr ( & self ) -> * const Char16 {
266
292
self . 0 . as_ptr ( )
@@ -378,110 +404,15 @@ impl PartialEq<CString16> for &CStr16 {
378
404
}
379
405
}
380
406
381
- /// An unaligned UCS-2 null-terminated string.
382
- ///
383
- /// This wrapper type can be used with UEFI strings that are inside a
384
- /// [`repr(packed)`] struct. Creating a reference to a packed field is
385
- /// not allowed because it might not be properly aligned, so a
386
- /// [`CStr16`] can't be directly constructed. `UnalignedCStr16` instead
387
- /// takes a pointer to the unaligned field, which is allowed. The
388
- /// resulting unaligned string cannot be used directly, but must be
389
- /// converted to an aligned form first with [`to_cstr16`] or
390
- /// [`to_cstring16`].
391
- ///
392
- /// [`repr(packed)`]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked
393
- /// [`to_cstr16`]: Self::to_cstr16
394
- /// [`to_cstring16`]: Self::to_cstring16
395
- #[ derive( Debug ) ]
396
- pub struct UnalignedCStr16 < ' a > {
397
- data : * const u16 ,
398
- len : usize ,
399
- _phantom_lifetime : PhantomData < & ' a ( ) > ,
400
- }
401
-
402
- // While it's not unsafe to have an empty `UnalignedCStr16`, there's not
403
- // much point either since the string wouldn't be valid without a null
404
- // terminator. So skip adding an `is_empty` method.
405
- #[ allow( clippy:: len_without_is_empty) ]
406
- impl < ' a > UnalignedCStr16 < ' a > {
407
- /// Create an `UnalignedCStr16` from a `*const u16` pointer. The
408
- /// pointer must be valid but can be unaligned. The `len` parameter
409
- /// is the number of `u16` characters in the string (not the number
410
- /// of bytes), including the trailing null.
411
- ///
412
- /// The `_lifetime` parameter is used to make it easy to set an
413
- /// appropriate lifetime for `'a`. The caller should pass in a
414
- /// reference to something tied to the lifetime of `data`. (The
415
- /// `data` parameter cannot itself be a reference because the
416
- /// pointer is allowed to be unaligned.)
417
- ///
418
- /// # Safety
419
- ///
420
- /// The `data` pointer cannot be dangling, and must remain valid for
421
- /// the lifetime of `'a`. There must be at least `len` `u16`
422
- /// elements starting with the the first character pointed to by
423
- /// `data`. These restrictions allow all other methods on
424
- /// `UnalignedCStr16` to be safe.
425
- pub unsafe fn new < T : ?Sized > ( _lifetime : & ' a T , data : * const u16 , len : usize ) -> Self {
426
- Self {
427
- data,
428
- len,
429
- _phantom_lifetime : PhantomData ,
430
- }
431
- }
432
-
433
- /// Number of `u16` elements in the string, including the trailing null.
434
- pub fn len ( & self ) -> usize {
435
- self . len
436
- }
437
-
438
- /// Copy the data to an aligned buffer. Panics if the length of
439
- /// `dst` is not exactly the same as `self.len()`. Otherwise the
440
- /// function always succeeds, and initializes all elements of `dst`.
441
- pub fn copy_to ( & self , dst : & mut [ MaybeUninit < u16 > ] ) {
442
- if dst. len ( ) != self . len {
443
- panic ! ( "incorrect buffer length" ) ;
444
- }
445
-
446
- for ( i, elem) in dst. iter_mut ( ) . enumerate ( ) {
447
- unsafe { elem. write ( self . data . add ( i) . read_unaligned ( ) ) } ;
448
- }
449
- }
450
-
451
- /// Convert to a [`CStr16`] using an aligned buffer for storage. The
452
- /// lifetime of the output is tied to `buf`, not `self`.
407
+ impl < ' a > UnalignedSlice < ' a , u16 > {
408
+ /// Create a [`CStr16`] from an [`UnalignedSlice`] using an aligned
409
+ /// buffer for storage. The lifetime of the output is tied to `buf`,
410
+ /// not `self`.
453
411
pub fn to_cstr16 < ' buf > (
454
412
& self ,
455
413
buf : & ' buf mut [ MaybeUninit < u16 > ] ,
456
414
) -> Result < & ' buf CStr16 , UnalignedCStr16Error > {
457
- // The input `buf` might be longer than needed, so get a
458
- // subslice of the required length.
459
- let buf = buf
460
- . get_mut ( ..self . len ( ) )
461
- . ok_or ( UnalignedCStr16Error :: BufferTooSmall ) ?;
462
-
463
- self . copy_to ( buf) ;
464
- let buf = unsafe {
465
- // Safety: `copy_buf` fully initializes the slice.
466
- MaybeUninit :: slice_assume_init_ref ( buf)
467
- } ;
468
- CStr16 :: from_u16_with_nul ( buf) . map_err ( |e| match e {
469
- FromSliceWithNulError :: InvalidChar ( v) => UnalignedCStr16Error :: InvalidChar ( v) ,
470
- FromSliceWithNulError :: InteriorNul ( v) => UnalignedCStr16Error :: InteriorNul ( v) ,
471
- FromSliceWithNulError :: NotNulTerminated => UnalignedCStr16Error :: NotNulTerminated ,
472
- } )
473
- }
474
-
475
- /// Convert to a [`CString16`]. Requires the `exts` feature.
476
- #[ cfg( feature = "exts" ) ]
477
- pub fn to_cstring16 ( & self ) -> Result < CString16 , FromSliceWithNulError > {
478
- let len = self . len ( ) ;
479
- let mut v = Vec :: with_capacity ( len) ;
480
- unsafe {
481
- self . copy_to ( v. spare_capacity_mut ( ) ) ;
482
- v. set_len ( len) ;
483
- }
484
- CString16 :: try_from ( v)
415
+ CStr16 :: from_unaligned_slice ( self , buf)
485
416
}
486
417
}
487
418
@@ -580,8 +511,8 @@ mod tests {
580
511
ptr. add ( 3 ) . write_unaligned ( b't' . into ( ) ) ;
581
512
ptr. add ( 4 ) . write_unaligned ( b'\0' . into ( ) ) ;
582
513
583
- // Create the `UnalignedCStr16 `.
584
- UnalignedCStr16 :: new ( & buf , ptr, 5 )
514
+ // Create the `UnalignedSlice `.
515
+ UnalignedSlice :: new ( ptr, 5 )
585
516
} ;
586
517
587
518
// Test `to_cstr16()` with too small of a buffer.
0 commit comments