11use super :: * ;
22
3- /// A WinRT string ([HSTRING](https://docs.microsoft.com/en-us/windows/win32/winrt/hstring))
4- /// is reference-counted and immutable.
3+ /// An ([HSTRING](https://docs.microsoft.com/en-us/windows/win32/winrt/hstring))
4+ /// is a reference-counted and immutable UTF-16 string type .
55#[ repr( transparent) ]
6- pub struct HSTRING ( Option < core :: ptr :: NonNull < Header > > ) ;
6+ pub struct HSTRING ( pub ( crate ) * mut HStringHeader ) ;
77
88impl HSTRING {
99 /// Create an empty `HSTRING`.
1010 ///
1111 /// This function does not allocate memory.
1212 pub const fn new ( ) -> Self {
13- Self ( None )
13+ Self ( core :: ptr :: null_mut ( ) )
1414 }
1515
1616 /// Returns `true` if the string is empty.
17- pub const fn is_empty ( & self ) -> bool {
17+ pub fn is_empty ( & self ) -> bool {
1818 // An empty HSTRING is represented by a null pointer.
19- self . 0 . is_none ( )
19+ self . 0 . is_null ( )
2020 }
2121
2222 /// Returns the length of the string. The length is measured in `u16`s (UTF-16 code units), not including the terminating null character.
2323 pub fn len ( & self ) -> usize {
24- if let Some ( header) = self . get_header ( ) {
24+ if let Some ( header) = self . as_header ( ) {
2525 header. len as usize
2626 } else {
2727 0
@@ -35,7 +35,7 @@ impl HSTRING {
3535
3636 /// Returns a raw pointer to the `HSTRING` buffer.
3737 pub fn as_ptr ( & self ) -> * const u16 {
38- if let Some ( header) = self . get_header ( ) {
38+ if let Some ( header) = self . as_header ( ) {
3939 header. data
4040 } else {
4141 const EMPTY : [ u16 ; 1 ] = [ 0 ] ;
@@ -66,7 +66,7 @@ impl HSTRING {
6666 return Ok ( Self :: new ( ) ) ;
6767 }
6868
69- let ptr = Header :: alloc ( len. try_into ( ) ?) ?;
69+ let ptr = HStringHeader :: alloc ( len. try_into ( ) ?) ?;
7070
7171 // Place each utf-16 character into the buffer and
7272 // increase len as we go along.
@@ -79,11 +79,11 @@ impl HSTRING {
7979
8080 // Write a 0 byte to the end of the buffer.
8181 ( * ptr) . data . offset ( ( * ptr) . len as isize ) . write ( 0 ) ;
82- Ok ( Self ( core :: ptr:: NonNull :: new ( ptr ) ) )
82+ Ok ( Self ( ptr) )
8383 }
8484
85- fn get_header ( & self ) -> Option < & Header > {
86- self . 0 . map ( |header| unsafe { header . as_ref ( ) } )
85+ fn as_header ( & self ) -> Option < & HStringHeader > {
86+ unsafe { self . 0 . as_ref ( ) }
8787 }
8888}
8989
@@ -95,8 +95,8 @@ impl Default for HSTRING {
9595
9696impl Clone for HSTRING {
9797 fn clone ( & self ) -> Self {
98- if let Some ( header) = self . get_header ( ) {
99- Self ( core :: ptr :: NonNull :: new ( header. duplicate ( ) . unwrap ( ) ) )
98+ if let Some ( header) = self . as_header ( ) {
99+ Self ( header. duplicate ( ) . unwrap ( ) )
100100 } else {
101101 Self :: new ( )
102102 }
@@ -105,17 +105,12 @@ impl Clone for HSTRING {
105105
106106impl Drop for HSTRING {
107107 fn drop ( & mut self ) {
108- if self . is_empty ( ) {
109- return ;
110- }
111-
112- if let Some ( header) = self . 0 . take ( ) {
113- // REFERENCE_FLAG indicates a string backed by static or stack memory that is
108+ if let Some ( header) = self . as_header ( ) {
109+ // HSTRING_REFERENCE_FLAG indicates a string backed by static or stack memory that is
114110 // thus not reference-counted and does not need to be freed.
115111 unsafe {
116- let header = header. as_ref ( ) ;
117- if header. flags & REFERENCE_FLAG == 0 && header. count . release ( ) == 0 {
118- heap_free ( header as * const _ as * mut _ ) ;
112+ if header. flags & HSTRING_REFERENCE_FLAG == 0 && header. count . release ( ) == 0 {
113+ HStringHeader :: free ( self . 0 ) ;
119114 }
120115 }
121116 }
@@ -407,54 +402,3 @@ impl From<HSTRING> for std::ffi::OsString {
407402 Self :: from ( & hstring)
408403 }
409404}
410-
411- const REFERENCE_FLAG : u32 = 1 ;
412-
413- #[ repr( C ) ]
414- struct Header {
415- flags : u32 ,
416- len : u32 ,
417- _0 : u32 ,
418- _1 : u32 ,
419- data : * mut u16 ,
420- count : RefCount ,
421- buffer_start : u16 ,
422- }
423-
424- impl Header {
425- fn alloc ( len : u32 ) -> Result < * mut Header > {
426- debug_assert ! ( len != 0 ) ;
427- // Allocate enough space for header and two bytes per character.
428- // The space for the terminating null character is already accounted for inside of `Header`.
429- let alloc_size = core:: mem:: size_of :: < Header > ( ) + 2 * len as usize ;
430-
431- let header = heap_alloc ( alloc_size) ? as * mut Header ;
432-
433- unsafe {
434- // Use `ptr::write` (since `header` is unintialized). `Header` is safe to be all zeros.
435- header. write ( core:: mem:: MaybeUninit :: < Header > :: zeroed ( ) . assume_init ( ) ) ;
436- ( * header) . len = len;
437- ( * header) . count = RefCount :: new ( 1 ) ;
438- ( * header) . data = & mut ( * header) . buffer_start ;
439- }
440-
441- Ok ( header)
442- }
443-
444- fn duplicate ( & self ) -> Result < * mut Header > {
445- if self . flags & REFERENCE_FLAG == 0 {
446- // If this is not a "fast pass" string then simply increment the reference count.
447- self . count . add_ref ( ) ;
448- Ok ( self as * const Header as * mut Header )
449- } else {
450- // Otherwise, allocate a new string and copy the value into the new string.
451- let copy = Header :: alloc ( self . len ) ?;
452- // SAFETY: since we are duplicating the string it is safe to copy all data from self to the initialized `copy`.
453- // We copy `len + 1` characters since `len` does not account for the terminating null character.
454- unsafe {
455- core:: ptr:: copy_nonoverlapping ( self . data , ( * copy) . data , self . len as usize + 1 ) ;
456- }
457- Ok ( copy)
458- }
459- }
460- }
0 commit comments