@@ -284,6 +284,40 @@ impl CStr16 {
284
284
& * ( codes as * const [ u16 ] as * const Self )
285
285
}
286
286
287
+ /// Creates a `&CStr16` from a [`Char16`] slice, if the slice is
288
+ /// null-terminated and has no interior null characters.
289
+ pub fn from_char16_with_nul ( chars : & [ Char16 ] ) -> Result < & Self , FromSliceWithNulError > {
290
+ // Fail early if the input is empty.
291
+ if chars. is_empty ( ) {
292
+ return Err ( FromSliceWithNulError :: NotNulTerminated ) ;
293
+ }
294
+
295
+ // Find the index of the first null char.
296
+ if let Some ( null_index) = chars. iter ( ) . position ( |c| * c == NUL_16 ) {
297
+ // Verify the null character is at the end.
298
+ if null_index == chars. len ( ) - 1 {
299
+ // Safety: the input is null-terminated and has no interior nulls.
300
+ Ok ( unsafe { Self :: from_char16_with_nul_unchecked ( chars) } )
301
+ } else {
302
+ Err ( FromSliceWithNulError :: InteriorNul ( null_index) )
303
+ }
304
+ } else {
305
+ Err ( FromSliceWithNulError :: NotNulTerminated )
306
+ }
307
+ }
308
+
309
+ /// Unsafely creates a `&CStr16` from a `Char16` slice.
310
+ ///
311
+ /// # Safety
312
+ ///
313
+ /// It's the callers responsibility to ensure chars is null-terminated and
314
+ /// has no interior null characters.
315
+ #[ must_use]
316
+ pub const unsafe fn from_char16_with_nul_unchecked ( chars : & [ Char16 ] ) -> & Self {
317
+ let ptr: * const [ Char16 ] = chars;
318
+ & * ( ptr as * const Self )
319
+ }
320
+
287
321
/// Convert a [`&str`] to a `&CStr16`, backed by a buffer.
288
322
///
289
323
/// The input string must contain only characters representable with
@@ -615,6 +649,45 @@ mod tests {
615
649
assert_eq ! ( s. num_bytes( ) , 8 ) ;
616
650
}
617
651
652
+ #[ test]
653
+ fn test_cstr16_from_char16_with_nul ( ) {
654
+ // Invalid: empty input.
655
+ assert_eq ! (
656
+ CStr16 :: from_char16_with_nul( & [ ] ) ,
657
+ Err ( FromSliceWithNulError :: NotNulTerminated )
658
+ ) ;
659
+
660
+ // Invalid: interior null.
661
+ assert_eq ! (
662
+ CStr16 :: from_char16_with_nul( & [
663
+ Char16 :: try_from( 'a' ) . unwrap( ) ,
664
+ NUL_16 ,
665
+ Char16 :: try_from( 'b' ) . unwrap( ) ,
666
+ NUL_16
667
+ ] ) ,
668
+ Err ( FromSliceWithNulError :: InteriorNul ( 1 ) )
669
+ ) ;
670
+
671
+ // Invalid: no trailing null.
672
+ assert_eq ! (
673
+ CStr16 :: from_char16_with_nul( & [
674
+ Char16 :: try_from( 'a' ) . unwrap( ) ,
675
+ Char16 :: try_from( 'b' ) . unwrap( ) ,
676
+ ] ) ,
677
+ Err ( FromSliceWithNulError :: NotNulTerminated )
678
+ ) ;
679
+
680
+ // Valid.
681
+ assert_eq ! (
682
+ CStr16 :: from_char16_with_nul( & [
683
+ Char16 :: try_from( 'a' ) . unwrap( ) ,
684
+ Char16 :: try_from( 'b' ) . unwrap( ) ,
685
+ NUL_16 ,
686
+ ] ) ,
687
+ Ok ( cstr16!( "ab" ) )
688
+ ) ;
689
+ }
690
+
618
691
#[ test]
619
692
fn test_cstr16_from_str_with_buf ( ) {
620
693
let mut buf = [ 0 ; 4 ] ;
0 commit comments