pub type Wtf16String = WtfString<Wtf16>;Expand description
A WtfString whose storage is WTF-16 (u16 code units).
Aliased Type§
pub struct Wtf16String { /* private fields */ }Implementations§
Source§impl Wtf16String
impl Wtf16String
Sourcepub fn from_os_str(s: &OsStr) -> Self
pub fn from_os_str(s: &OsStr) -> Self
Encode an OsStr into owned WTF-16, converting once at the boundary.
Lossless: unpaired surrogates survive, so
from_os_str(x).to_os_string() == x. This is the owning analog of
collecting OsStrExt::encode_wide.
Sourcepub fn from_wide(units: &[u16]) -> Self
pub fn from_wide(units: &[u16]) -> Self
Build from already-wide code units: the OsStringExt::from_wide analog.
Identical to from_units, named for drop-in
familiarity when replacing an OsString::from_wide call site.
Source§impl Wtf16String
impl Wtf16String
Sourcepub fn as_terminated_ptr(&self) -> *const u16
pub fn as_terminated_ptr(&self) -> *const u16
A NUL-terminated *const u16 (LPCWSTR/PCWSTR) over the whole buffer.
The always-present terminator makes this allocation-free (D-7). It is a
valid C string only when has_interior_nul is
false; otherwise a reader stops at the first interior NUL. The pointer is
valid while self is borrowed and unmodified.
Examples found in repository?
92 fn full_path(input: &Wtf16String) -> Option<Wtf16String> {
93 // Pass 1: ask for the size. The terminator is already in the buffer, so
94 // handing over an `LPCWSTR` costs nothing.
95 // SAFETY: `as_terminated_ptr` is NUL-terminated and valid while
96 // `input` is borrowed; a zero length asks for the required size only.
97 let needed = unsafe {
98 GetFullPathNameW(
99 input.as_terminated_ptr(),
100 0,
101 core::ptr::null_mut(),
102 core::ptr::null_mut(),
103 )
104 };
105 if needed == 0 {
106 return None;
107 }
108
109 // `needed` counts the terminator; our capacity is a *content* length,
110 // and `with_capacity` reserves the terminator slot itself.
111 let mut out = Wtf16String::with_capacity(needed as usize - 1);
112
113 // Pass 2: let the API write straight into our buffer.
114 // SAFETY: the buffer has room for `needed` units (content + the
115 // reserved terminator slot), which is exactly what pass 1 asked for.
116 let written = unsafe {
117 GetFullPathNameW(
118 input.as_terminated_ptr(),
119 needed,
120 out.as_mut_ptr(),
121 core::ptr::null_mut(),
122 )
123 };
124 if written == 0 || written >= needed {
125 // Failed, or raced a directory change and now wants more room.
126 // `out`'s invariant is still broken here, so republish an empty
127 // string before dropping it (see `as_mut_ptr`'s contract).
128 // SAFETY: publishing zero content units is always in bounds.
129 unsafe { out.set_len_from_ffi(0) };
130 return None;
131 }
132
133 // `written` excludes the terminator, which is precisely the content
134 // length `set_len_from_ffi` wants -- no guessing about conventions.
135 // SAFETY: the API initialized `written` units and `written < needed`,
136 // so the appended terminator still fits.
137 unsafe { out.set_len_from_ffi(written as usize) };
138 Some(out)
139 }Sourcepub fn with_capacity(units: usize) -> Self
pub fn with_capacity(units: usize) -> Self
An empty string with room for units content code units to be filled in
place via as_mut_ptr plus
set_len_from_ffi.
The reserved capacity also covers the always-present terminator, so a
later set_len_from_ffi of up to units content
units re-establishes the invariant without reallocating (D-9).
Examples found in repository?
92 fn full_path(input: &Wtf16String) -> Option<Wtf16String> {
93 // Pass 1: ask for the size. The terminator is already in the buffer, so
94 // handing over an `LPCWSTR` costs nothing.
95 // SAFETY: `as_terminated_ptr` is NUL-terminated and valid while
96 // `input` is borrowed; a zero length asks for the required size only.
97 let needed = unsafe {
98 GetFullPathNameW(
99 input.as_terminated_ptr(),
100 0,
101 core::ptr::null_mut(),
102 core::ptr::null_mut(),
103 )
104 };
105 if needed == 0 {
106 return None;
107 }
108
109 // `needed` counts the terminator; our capacity is a *content* length,
110 // and `with_capacity` reserves the terminator slot itself.
111 let mut out = Wtf16String::with_capacity(needed as usize - 1);
112
113 // Pass 2: let the API write straight into our buffer.
114 // SAFETY: the buffer has room for `needed` units (content + the
115 // reserved terminator slot), which is exactly what pass 1 asked for.
116 let written = unsafe {
117 GetFullPathNameW(
118 input.as_terminated_ptr(),
119 needed,
120 out.as_mut_ptr(),
121 core::ptr::null_mut(),
122 )
123 };
124 if written == 0 || written >= needed {
125 // Failed, or raced a directory change and now wants more room.
126 // `out`'s invariant is still broken here, so republish an empty
127 // string before dropping it (see `as_mut_ptr`'s contract).
128 // SAFETY: publishing zero content units is always in bounds.
129 unsafe { out.set_len_from_ffi(0) };
130 return None;
131 }
132
133 // `written` excludes the terminator, which is precisely the content
134 // length `set_len_from_ffi` wants -- no guessing about conventions.
135 // SAFETY: the API initialized `written` units and `written < needed`,
136 // so the appended terminator still fits.
137 unsafe { out.set_len_from_ffi(written as usize) };
138 Some(out)
139 }Sourcepub fn as_mut_ptr(&mut self) -> *mut u16
pub fn as_mut_ptr(&mut self) -> *mut u16
A mutable pointer to the start of the buffer, for a foreign buffer-fill.
with_capacity(n) reserves n + 1 units: room
for n content units plus the terminator slot. A foreign API may fill up
to n content units, and one more if it writes its own terminator into
the reserved slot (n + 1 units total). Either way, pass only the
content length to set_len_from_ffi, which
publishes that length and re-establishes the terminator.
Writing through this pointer overwrites the buffer – including element 0,
which is the sole terminator of a fresh with_capacity – so it breaks
the always-terminated invariant until
set_len_from_ffi restores it. Between the write
and that call the value must not be observed through any other method
(as_terminated_ptr, Deref content access,
Clone, Debug, PartialEq, …): they could read a non-terminated or
partially written buffer. This holds on failure paths too – if the
foreign call fails, restore the invariant with set_len_from_ffi(0) (the
empty string) or drop the value before any other use. The pointer is valid
while self is borrowed and not reallocated.
Examples found in repository?
92 fn full_path(input: &Wtf16String) -> Option<Wtf16String> {
93 // Pass 1: ask for the size. The terminator is already in the buffer, so
94 // handing over an `LPCWSTR` costs nothing.
95 // SAFETY: `as_terminated_ptr` is NUL-terminated and valid while
96 // `input` is borrowed; a zero length asks for the required size only.
97 let needed = unsafe {
98 GetFullPathNameW(
99 input.as_terminated_ptr(),
100 0,
101 core::ptr::null_mut(),
102 core::ptr::null_mut(),
103 )
104 };
105 if needed == 0 {
106 return None;
107 }
108
109 // `needed` counts the terminator; our capacity is a *content* length,
110 // and `with_capacity` reserves the terminator slot itself.
111 let mut out = Wtf16String::with_capacity(needed as usize - 1);
112
113 // Pass 2: let the API write straight into our buffer.
114 // SAFETY: the buffer has room for `needed` units (content + the
115 // reserved terminator slot), which is exactly what pass 1 asked for.
116 let written = unsafe {
117 GetFullPathNameW(
118 input.as_terminated_ptr(),
119 needed,
120 out.as_mut_ptr(),
121 core::ptr::null_mut(),
122 )
123 };
124 if written == 0 || written >= needed {
125 // Failed, or raced a directory change and now wants more room.
126 // `out`'s invariant is still broken here, so republish an empty
127 // string before dropping it (see `as_mut_ptr`'s contract).
128 // SAFETY: publishing zero content units is always in bounds.
129 unsafe { out.set_len_from_ffi(0) };
130 return None;
131 }
132
133 // `written` excludes the terminator, which is precisely the content
134 // length `set_len_from_ffi` wants -- no guessing about conventions.
135 // SAFETY: the API initialized `written` units and `written < needed`,
136 // so the appended terminator still fits.
137 unsafe { out.set_len_from_ffi(written as usize) };
138 Some(out)
139 }Sourcepub unsafe fn set_len_from_ffi(&mut self, content_units: usize)
pub unsafe fn set_len_from_ffi(&mut self, content_units: usize)
Publish content_units content code units written into the buffer from
as_mut_ptr, then append the terminator.
content_units counts content only and never includes a terminator.
The written units are taken verbatim – they may themselves end in NUL,
since interior NULs are permitted (see
has_interior_nul) – and exactly one
terminator is appended. A foreign API that reports a count including the
terminator it wrote must subtract one and pass the content length; this
method never inspects the buffer to guess the convention, so a genuine
trailing content NUL is never mistaken for the terminator.
§Safety
The caller must guarantee that:
- the first
content_unitscode units atas_mut_ptrare initializedu16values, and content_unitsdoes not exceed the count requested viawith_capacity, so the appended terminator fits without reallocating a buffer whose pointer the caller may still hold.
Examples found in repository?
92 fn full_path(input: &Wtf16String) -> Option<Wtf16String> {
93 // Pass 1: ask for the size. The terminator is already in the buffer, so
94 // handing over an `LPCWSTR` costs nothing.
95 // SAFETY: `as_terminated_ptr` is NUL-terminated and valid while
96 // `input` is borrowed; a zero length asks for the required size only.
97 let needed = unsafe {
98 GetFullPathNameW(
99 input.as_terminated_ptr(),
100 0,
101 core::ptr::null_mut(),
102 core::ptr::null_mut(),
103 )
104 };
105 if needed == 0 {
106 return None;
107 }
108
109 // `needed` counts the terminator; our capacity is a *content* length,
110 // and `with_capacity` reserves the terminator slot itself.
111 let mut out = Wtf16String::with_capacity(needed as usize - 1);
112
113 // Pass 2: let the API write straight into our buffer.
114 // SAFETY: the buffer has room for `needed` units (content + the
115 // reserved terminator slot), which is exactly what pass 1 asked for.
116 let written = unsafe {
117 GetFullPathNameW(
118 input.as_terminated_ptr(),
119 needed,
120 out.as_mut_ptr(),
121 core::ptr::null_mut(),
122 )
123 };
124 if written == 0 || written >= needed {
125 // Failed, or raced a directory change and now wants more room.
126 // `out`'s invariant is still broken here, so republish an empty
127 // string before dropping it (see `as_mut_ptr`'s contract).
128 // SAFETY: publishing zero content units is always in bounds.
129 unsafe { out.set_len_from_ffi(0) };
130 return None;
131 }
132
133 // `written` excludes the terminator, which is precisely the content
134 // length `set_len_from_ffi` wants -- no guessing about conventions.
135 // SAFETY: the API initialized `written` units and `written < needed`,
136 // so the appended terminator still fits.
137 unsafe { out.set_len_from_ffi(written as usize) };
138 Some(out)
139 }Sourcepub unsafe fn from_wide_ptr(ptr: *const u16, len: usize) -> Self
pub unsafe fn from_wide_ptr(ptr: *const u16, len: usize) -> Self
Copy len content code units from a foreign *const u16 into a new owned
string, appending the terminator.
For callee-allocated Win32 output: the bytes are copied, so the caller keeps ownership of (and remains responsible for freeing) the source buffer. The copy is lossless — arbitrary WTF-16, including unpaired surrogates, is preserved (D-4/D-9).
§Safety
This copies the range through core::slice::from_raw_parts and shares its
preconditions. When len > 0 the caller must guarantee that:
ptris non-null and properly aligned foru16;ptris valid for reads oflenconsecutive, initializedu16values, all contained within a single allocated object;- the total size
len * size_of::<u16>()is no larger thanisize::MAX, and adding it toptrdoes not wrap the address space; and - that region stays unmutated for the duration of the call.
When len == 0 the pointer is not dereferenced, so it may be null or
dangling. No reference to ptr is retained past the call. len is a
count of code units, not bytes, and excludes any terminator the callee
may have written (pass the content length).
Trait Implementations§
Source§impl From<&OsStr> for Wtf16String
impl From<&OsStr> for Wtf16String
Source§impl From<&OsString> for Wtf16String
impl From<&OsString> for Wtf16String
Source§impl From<OsString> for Wtf16String
impl From<OsString> for Wtf16String
impl Param<PCWSTR> for &Wtf16String
Pass a &Wtf16String directly to a windows API taking impl Param<PCWSTR>.
The pointer handed over is as_terminated_ptr:
no conversion, no allocation, and no copy. It stays valid for the call because
the borrow keeps the owning Wtf16String alive and unmodified.
This carries exactly the C-string caveat of the pointer it wraps (D-7): the
callee stops at the first NUL, so a value with an interior NUL is seen
truncated. Check has_interior_nul first
when the content may contain one. &HSTRING’s own Param<PCWSTR> impl has
the same property, so this is parity with the ecosystem, not a new hazard.
There is deliberately no impl for &Wtf16Str: a borrowed slice carries no
terminator (D-7), so it has no valid PCWSTR to give. Borrowed content
reaches Win32 through the counted pair
as_ptr + len instead.