1use std::fmt::Write;
7
8#[repr(transparent)]
9#[derive(Clone, Copy, PartialEq, Eq, Debug)]
10pub struct PCWSTR(pub *const u16);
11
12impl AsRef<PCWSTR> for PCWSTR {
13 fn as_ref(&self) -> &Self {
14 self
15 }
16}
17
18impl windows_core::TypeKind for PCWSTR {
19 type TypeKind = windows_core::CopyType;
20}
21
22impl PCWSTR {
25 pub const fn from_raw(ptr: *const u16) -> Self {
27 Self(ptr)
28 }
29
30 pub const fn null() -> Self {
32 Self(core::ptr::null())
33 }
34
35 pub const fn as_ptr(&self) -> *const u16 {
37 self.0
38 }
39
40 pub fn is_null(&self) -> bool {
42 self.0.is_null()
43 }
44
45 pub unsafe fn len(&self) -> usize {
51 let mut len = 0;
52 let mut ptr = self.0;
53 while ptr.read() != 0 {
54 len += 1;
55 ptr = ptr.add(1);
56 }
57 len
58 }
59
60 pub unsafe fn is_empty(&self) -> bool {
66 self.len() == 0
67 }
68
69 pub unsafe fn as_wide(&self) -> &[u16] {
75 core::slice::from_raw_parts(self.0, self.len())
76 }
77}
78
79#[repr(transparent)]
80#[derive(Clone, Copy, PartialEq, Eq, Debug)]
81pub struct PCSTR(pub *const u8);
82
83impl AsRef<PCSTR> for PCSTR {
84 fn as_ref(&self) -> &Self {
85 self
86 }
87}
88
89impl windows_core::TypeKind for PCSTR {
90 type TypeKind = windows_core::CopyType;
91}
92
93#[derive(Clone, PartialEq, Eq, Default)]
97pub struct WString(Option<Vec<u16>>);
98const EMPTY: [u16; 1] = [0];
99
100impl WString {
101 pub const fn new() -> Self {
103 Self(None)
104 }
105
106 pub const fn is_empty(&self) -> bool {
108 self.0.is_none()
109 }
110
111 pub fn len(&self) -> usize {
113 match self.0.as_ref() {
114 Some(v) => v.len() - 1,
115 None => 0,
116 }
117 }
118
119 pub fn as_wide(&self) -> &[u16] {
121 match self.0.as_ref() {
122 Some(v) => {
123 v.as_slice().split_last().unwrap().1
125 }
126 None => &[],
127 }
128 }
129
130 pub fn to_string_lossy(&self) -> String {
132 String::from_utf16_lossy(self.as_wide())
133 }
134
135 pub fn as_ptr(&self) -> *const u16 {
137 match self.0.as_ref() {
138 Some(v) => v.as_ptr(),
139 None => EMPTY.as_ptr(),
140 }
141 }
142
143 pub fn as_pcwstr(&self) -> PCWSTR {
144 PCWSTR::from_raw(self.as_ptr())
145 }
146
147 pub fn from_wide(value: &[u16]) -> Self {
149 unsafe { Self::from_wide_iter(value.iter().cloned(), value.len()) }
151 }
152
153 unsafe fn from_wide_iter<I: Iterator<Item = u16>>(iter: I, len: usize) -> Self {
154 if len == 0 {
155 return Self::new();
156 }
157 let iter = iter.chain(EMPTY.as_ref().iter().cloned());
159 let v = iter.collect::<Vec<_>>();
160 Self(Some(v))
161 }
162}
163
164impl From<&str> for WString {
165 fn from(value: &str) -> Self {
166 unsafe { Self::from_wide_iter(value.encode_utf16(), value.len()) }
167 }
168}
169
170impl From<String> for WString {
171 fn from(value: String) -> Self {
172 value.as_str().into()
173 }
174}
175impl From<&String> for WString {
176 fn from(value: &String) -> Self {
177 value.as_str().into()
178 }
179}
180
181impl core::fmt::Display for WString {
182 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
183 let wit = core::char::decode_utf16(self.as_wide().iter().cloned());
185 for c in wit {
186 match c {
187 Ok(c) => f.write_char(c)?,
188 Err(_) => f.write_char(core::char::REPLACEMENT_CHARACTER)?,
189 }
190 }
191 Ok(())
192 }
193}
194
195impl core::fmt::Debug for WString {
196 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197 write!(f, "\"{}\"", self)
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use crate::PCWSTR;
204
205 use super::WString;
206
207 #[test]
208 fn string_test() {
209 let test_case = |s: &str| {
210 let h = WString::from(s);
211 assert_eq!(s.len(), h.len());
212 assert_eq!(s.is_empty(), h.is_empty());
213 assert_eq!(format!("{}", h), s);
214 assert_eq!(s, h.to_string_lossy());
215 assert_eq!(h.as_wide().len(), s.len());
216 let raw = h.as_ptr();
217 let h2 = WString::from_wide(unsafe { PCWSTR(raw).as_wide() });
218 assert_eq!(s, h2.to_string_lossy());
219 assert_eq!(h, h2);
220 assert_ne!(h, WString::from("dummy"));
221 };
222
223 test_case("hello");
224 test_case("s");
225 test_case("");
226 }
227}