pub struct WtfStr<E: WtfEncoding> { /* private fields */ }Expand description
A borrowed string slice of code units in encoding E (the analog of
OsStr / str).
This is #[repr(transparent)] over [E::Unit], so a &WtfStr<E> can be
created from a &[E::Unit] without copying. The units are the string’s
content: there is no terminator here, since the always-terminated invariant
is a property of the owned WtfString, not of an arbitrary borrowed slice.
Implementations§
Source§impl WtfStr<Wtf16>
impl WtfStr<Wtf16>
Sourcepub fn to_os_string(&self) -> OsString
pub fn to_os_string(&self) -> OsString
Decode the content into an owned OsString, losslessly.
The OsStringExt::from_wide bridge: unpaired surrogates are preserved.
Sourcepub fn encode_wide(&self) -> impl Iterator<Item = u16> + '_
pub fn encode_wide(&self) -> impl Iterator<Item = u16> + '_
Iterate the content as wide code units, zero-copy: the
OsStrExt::encode_wide analog over our own slice.
Source§impl<E: WtfEncoding> WtfStr<E>
impl<E: WtfEncoding> WtfStr<E>
Sourcepub fn from_units(units: &[E::Unit]) -> &WtfStr<E>
pub fn from_units(units: &[E::Unit]) -> &WtfStr<E>
Wrap a slice of code units as a &WtfStr<E> without copying.
Examples found in repository?
67 pub fn run() {
68 let input = Wtf16String::from(r"C:\Windows\System32\..\Temp");
69 println!("input : {input}");
70
71 match full_path(&input) {
72 Some(expanded) => println!("expanded: {expanded}"),
73 None => println!("expanded: <GetFullPathNameW failed>"),
74 }
75
76 compare(&Wtf16String::from("alpha"), &Wtf16String::from("beta"));
77 compare(&Wtf16String::from("beta"), &Wtf16String::from("alpha"));
78 compare(&Wtf16String::from("same"), &Wtf16String::from("same"));
79
80 // The counted pair works on a borrowed slice, which has no terminator
81 // of its own -- the length is what makes it well-defined.
82 let units: Vec<u16> = "borrowed".encode_utf16().collect();
83 let borrowed = Wtf16Str::from_units(&units);
84 println!(
85 "borrowed slice of {} units compares equal to itself: {}",
86 borrowed.len(),
87 ordinal(borrowed, borrowed) == CSTR_EQUAL
88 );
89 }Sourcepub fn as_units(&self) -> &[E::Unit]
pub fn as_units(&self) -> &[E::Unit]
The content code units (there is no terminator on a borrowed slice).
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
The number of content code units (not bytes, not code points).
Examples found in repository?
67 pub fn run() {
68 let input = Wtf16String::from(r"C:\Windows\System32\..\Temp");
69 println!("input : {input}");
70
71 match full_path(&input) {
72 Some(expanded) => println!("expanded: {expanded}"),
73 None => println!("expanded: <GetFullPathNameW failed>"),
74 }
75
76 compare(&Wtf16String::from("alpha"), &Wtf16String::from("beta"));
77 compare(&Wtf16String::from("beta"), &Wtf16String::from("alpha"));
78 compare(&Wtf16String::from("same"), &Wtf16String::from("same"));
79
80 // The counted pair works on a borrowed slice, which has no terminator
81 // of its own -- the length is what makes it well-defined.
82 let units: Vec<u16> = "borrowed".encode_utf16().collect();
83 let borrowed = Wtf16Str::from_units(&units);
84 println!(
85 "borrowed slice of {} units compares equal to itself: {}",
86 borrowed.len(),
87 ordinal(borrowed, borrowed) == CSTR_EQUAL
88 );
89 }
90
91 /// Terminated input, then buffer-fill output -- both without converting.
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 }
140
141 /// Counted input: pointer + length, no terminator required.
142 fn ordinal(a: &Wtf16Str, b: &Wtf16Str) -> i32 {
143 // SAFETY: each pointer is valid for exactly its own `len()` units while
144 // borrowed, which is the contract `CompareStringOrdinal` expects.
145 unsafe {
146 CompareStringOrdinal(
147 a.as_ptr(),
148 a.len() as i32,
149 b.as_ptr(),
150 b.len() as i32,
151 0, // case-sensitive
152 )
153 }
154 }Sourcepub fn has_interior_nul(&self) -> bool
pub fn has_interior_nul(&self) -> bool
Whether the content contains a NUL (E::NUL) code unit.
For the Wtf16 arm, a terminated LPCWSTR view of an owned string is a
valid C string only when this is false (see
Wtf16String::as_terminated_ptr); counted access is always valid
regardless of this encoding’s storage width.
Sourcepub fn to_string_checked(&self) -> Option<String>
pub fn to_string_checked(&self) -> Option<String>
Decode to a String if the content is well-formed for this encoding.
Returns None for content a strict String cannot hold (e.g. an unpaired
surrogate in WTF-16); use to_string_lossy to
decode with replacement instead.
Sourcepub fn to_string_lossy(&self) -> String
pub fn to_string_lossy(&self) -> String
Decode to a String, replacing any ill-formed sequence with U+FFFD.
Source§impl WtfStr<Wtf16>
impl WtfStr<Wtf16>
Sourcepub fn as_ptr(&self) -> *const u16
pub fn as_ptr(&self) -> *const u16
A pointer to the content code units, for counted FFI paired with
len.
The pointer is not guaranteed to be NUL-terminated (a borrowed slice
carries no terminator); use it only with the matching unit count. It is
valid while self is borrowed and unmodified. For a terminated
LPCWSTR, start from an owned Wtf16String and use
Wtf16String::as_terminated_ptr.
Examples found in repository?
142 fn ordinal(a: &Wtf16Str, b: &Wtf16Str) -> i32 {
143 // SAFETY: each pointer is valid for exactly its own `len()` units while
144 // borrowed, which is the contract `CompareStringOrdinal` expects.
145 unsafe {
146 CompareStringOrdinal(
147 a.as_ptr(),
148 a.len() as i32,
149 b.as_ptr(),
150 b.len() as i32,
151 0, // case-sensitive
152 )
153 }
154 }