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