windows_strings/
hstring.rs1use super::*;
2use core::ops::Deref;
3
4#[repr(transparent)]
7pub struct HSTRING(pub(crate) *mut HStringHeader);
8
9impl HSTRING {
10 pub const fn new() -> Self {
12 Self(core::ptr::null_mut())
13 }
14
15 pub fn from_wide(value: &[u16]) -> Self {
17 unsafe { Self::from_wide_iter(value.iter().copied(), value.len()) }
18 }
19
20 pub fn to_string_lossy(&self) -> String {
22 String::from_utf16_lossy(self)
23 }
24
25 #[cfg(all(feature = "std", windows))]
27 pub fn to_os_string(&self) -> std::ffi::OsString {
28 std::os::windows::ffi::OsStringExt::from_wide(self)
29 }
30
31 pub fn display(&self) -> impl core::fmt::Display + '_ {
33 Decode(move || core::char::decode_utf16(self.iter().copied()))
34 }
35
36 unsafe fn from_wide_iter<I: Iterator<Item = u16>>(iter: I, len: usize) -> Self {
39 if len == 0 {
40 return Self::new();
41 }
42
43 let ptr = HStringHeader::alloc(len.try_into().unwrap());
44
45 for (index, wide) in iter.enumerate() {
46 debug_assert!(index < len);
47
48 unsafe {
49 (*ptr).data.add(index).write(wide);
50 (*ptr).len = index as u32 + 1;
51 }
52 }
53
54 unsafe {
55 (*ptr).data.offset((*ptr).len as isize).write(0);
56 }
57 Self(ptr)
58 }
59
60 fn as_header(&self) -> Option<&HStringHeader> {
61 unsafe { self.0.as_ref() }
62 }
63}
64
65impl Deref for HSTRING {
66 type Target = [u16];
67
68 fn deref(&self) -> &[u16] {
69 if let Some(header) = self.as_header() {
70 unsafe { core::slice::from_raw_parts(header.data, header.len as usize) }
71 } else {
72 const EMPTY: [u16; 1] = [0];
74 &EMPTY[..0]
75 }
76 }
77}
78
79impl Default for HSTRING {
80 fn default() -> Self {
81 Self::new()
82 }
83}
84
85impl Clone for HSTRING {
86 fn clone(&self) -> Self {
87 if let Some(header) = self.as_header() {
88 Self(header.duplicate())
89 } else {
90 Self::new()
91 }
92 }
93}
94
95impl Drop for HSTRING {
96 fn drop(&mut self) {
97 if let Some(header) = self.as_header() {
98 unsafe {
100 if header.flags & HSTRING_REFERENCE_FLAG == 0 && header.count.release() == 0 {
101 HStringHeader::free(self.0);
102 }
103 }
104 }
105 }
106}
107
108unsafe impl Send for HSTRING {}
109unsafe impl Sync for HSTRING {}
110
111impl core::fmt::Debug for HSTRING {
112 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
113 write!(f, "{}", self.display())
114 }
115}
116
117impl From<&str> for HSTRING {
118 fn from(value: &str) -> Self {
119 unsafe { Self::from_wide_iter(value.encode_utf16(), value.len()) }
120 }
121}
122
123impl From<String> for HSTRING {
124 fn from(value: String) -> Self {
125 value.as_str().into()
126 }
127}
128
129impl From<&String> for HSTRING {
130 fn from(value: &String) -> Self {
131 value.as_str().into()
132 }
133}
134
135#[cfg(all(feature = "std", windows))]
136impl From<&std::path::Path> for HSTRING {
137 fn from(value: &std::path::Path) -> Self {
138 value.as_os_str().into()
139 }
140}
141
142#[cfg(all(feature = "std", windows))]
143impl From<&std::ffi::OsStr> for HSTRING {
144 fn from(value: &std::ffi::OsStr) -> Self {
145 unsafe {
146 Self::from_wide_iter(
147 std::os::windows::ffi::OsStrExt::encode_wide(value),
148 value.len(),
149 )
150 }
151 }
152}
153
154#[cfg(all(feature = "std", windows))]
155impl From<std::ffi::OsString> for HSTRING {
156 fn from(value: std::ffi::OsString) -> Self {
157 value.as_os_str().into()
158 }
159}
160
161#[cfg(all(feature = "std", windows))]
162impl From<&std::ffi::OsString> for HSTRING {
163 fn from(value: &std::ffi::OsString) -> Self {
164 value.as_os_str().into()
165 }
166}
167
168impl Eq for HSTRING {}
169
170impl Ord for HSTRING {
171 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
172 self.deref().cmp(other)
173 }
174}
175
176impl core::hash::Hash for HSTRING {
177 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
178 self.deref().hash(hasher);
179 }
180}
181
182impl PartialOrd for HSTRING {
183 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
184 Some(self.cmp(other))
185 }
186}
187
188impl PartialEq for HSTRING {
189 fn eq(&self, other: &Self) -> bool {
190 self.deref() == other.deref()
191 }
192}
193
194impl PartialEq<String> for HSTRING {
195 fn eq(&self, other: &String) -> bool {
196 *self == **other
197 }
198}
199
200impl PartialEq<String> for &HSTRING {
201 fn eq(&self, other: &String) -> bool {
202 **self == **other
203 }
204}
205
206impl PartialEq<&String> for HSTRING {
207 fn eq(&self, other: &&String) -> bool {
208 *self == ***other
209 }
210}
211
212impl PartialEq<str> for HSTRING {
213 fn eq(&self, other: &str) -> bool {
214 self.iter().copied().eq(other.encode_utf16())
215 }
216}
217
218impl PartialEq<str> for &HSTRING {
219 fn eq(&self, other: &str) -> bool {
220 **self == *other
221 }
222}
223
224impl PartialEq<&str> for HSTRING {
225 fn eq(&self, other: &&str) -> bool {
226 *self == **other
227 }
228}
229
230impl PartialEq<HSTRING> for str {
231 fn eq(&self, other: &HSTRING) -> bool {
232 *other == *self
233 }
234}
235
236impl PartialEq<HSTRING> for &str {
237 fn eq(&self, other: &HSTRING) -> bool {
238 *other == **self
239 }
240}
241
242impl PartialEq<&HSTRING> for str {
243 fn eq(&self, other: &&HSTRING) -> bool {
244 **other == *self
245 }
246}
247
248impl PartialEq<HSTRING> for String {
249 fn eq(&self, other: &HSTRING) -> bool {
250 *other == **self
251 }
252}
253
254impl PartialEq<HSTRING> for &String {
255 fn eq(&self, other: &HSTRING) -> bool {
256 *other == ***self
257 }
258}
259
260impl PartialEq<&HSTRING> for String {
261 fn eq(&self, other: &&HSTRING) -> bool {
262 **other == **self
263 }
264}
265
266#[cfg(all(feature = "std", windows))]
267impl PartialEq<std::ffi::OsString> for HSTRING {
268 fn eq(&self, other: &std::ffi::OsString) -> bool {
269 *self == **other
270 }
271}
272
273#[cfg(all(feature = "std", windows))]
274impl PartialEq<std::ffi::OsString> for &HSTRING {
275 fn eq(&self, other: &std::ffi::OsString) -> bool {
276 **self == **other
277 }
278}
279
280#[cfg(all(feature = "std", windows))]
281impl PartialEq<&std::ffi::OsString> for HSTRING {
282 fn eq(&self, other: &&std::ffi::OsString) -> bool {
283 *self == ***other
284 }
285}
286
287#[cfg(all(feature = "std", windows))]
288impl PartialEq<std::ffi::OsStr> for HSTRING {
289 fn eq(&self, other: &std::ffi::OsStr) -> bool {
290 self.iter()
291 .copied()
292 .eq(std::os::windows::ffi::OsStrExt::encode_wide(other))
293 }
294}
295
296#[cfg(all(feature = "std", windows))]
297impl PartialEq<std::ffi::OsStr> for &HSTRING {
298 fn eq(&self, other: &std::ffi::OsStr) -> bool {
299 **self == *other
300 }
301}
302
303#[cfg(all(feature = "std", windows))]
304impl PartialEq<&std::ffi::OsStr> for HSTRING {
305 fn eq(&self, other: &&std::ffi::OsStr) -> bool {
306 *self == **other
307 }
308}
309
310#[cfg(all(feature = "std", windows))]
311impl PartialEq<HSTRING> for std::ffi::OsStr {
312 fn eq(&self, other: &HSTRING) -> bool {
313 *other == *self
314 }
315}
316
317#[cfg(all(feature = "std", windows))]
318impl PartialEq<HSTRING> for &std::ffi::OsStr {
319 fn eq(&self, other: &HSTRING) -> bool {
320 *other == **self
321 }
322}
323
324#[cfg(all(feature = "std", windows))]
325impl PartialEq<&HSTRING> for std::ffi::OsStr {
326 fn eq(&self, other: &&HSTRING) -> bool {
327 **other == *self
328 }
329}
330
331#[cfg(all(feature = "std", windows))]
332impl PartialEq<HSTRING> for std::ffi::OsString {
333 fn eq(&self, other: &HSTRING) -> bool {
334 *other == **self
335 }
336}
337
338#[cfg(all(feature = "std", windows))]
339impl PartialEq<HSTRING> for &std::ffi::OsString {
340 fn eq(&self, other: &HSTRING) -> bool {
341 *other == ***self
342 }
343}
344
345#[cfg(all(feature = "std", windows))]
346impl PartialEq<&HSTRING> for std::ffi::OsString {
347 fn eq(&self, other: &&HSTRING) -> bool {
348 **other == **self
349 }
350}
351
352impl TryFrom<&HSTRING> for String {
353 type Error = alloc::string::FromUtf16Error;
354
355 fn try_from(hstring: &HSTRING) -> Result<Self, Self::Error> {
356 Self::from_utf16(hstring)
357 }
358}
359
360impl TryFrom<HSTRING> for String {
361 type Error = alloc::string::FromUtf16Error;
362
363 fn try_from(hstring: HSTRING) -> Result<Self, Self::Error> {
364 Self::try_from(&hstring)
365 }
366}
367
368#[cfg(all(feature = "std", windows))]
369impl From<&HSTRING> for std::ffi::OsString {
370 fn from(hstring: &HSTRING) -> Self {
371 hstring.to_os_string()
372 }
373}
374
375#[cfg(all(feature = "std", windows))]
376impl From<HSTRING> for std::ffi::OsString {
377 fn from(hstring: HSTRING) -> Self {
378 Self::from(&hstring)
379 }
380}