1 | use super::*; |
2 | |
3 | /// A BSTR string ([BSTR](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/automat/string-manipulation-functions)) |
4 | /// is a length-prefixed wide string. |
5 | #[repr (transparent)] |
6 | pub struct BSTR(*const u16); |
7 | |
8 | impl BSTR { |
9 | /// Create an empty `BSTR`. |
10 | /// |
11 | /// This function does not allocate memory. |
12 | pub const fn new() -> Self { |
13 | Self(std::ptr::null_mut()) |
14 | } |
15 | |
16 | /// Returns `true` if the string is empty. |
17 | pub fn is_empty(&self) -> bool { |
18 | self.len() == 0 |
19 | } |
20 | |
21 | /// Returns the length of the string. |
22 | pub fn len(&self) -> usize { |
23 | if self.0.is_null() { |
24 | 0 |
25 | } else { |
26 | unsafe { crate::imp::SysStringLen(self.0) as usize } |
27 | } |
28 | } |
29 | |
30 | /// Get the string as 16-bit wide characters (wchars). |
31 | pub fn as_wide(&self) -> &[u16] { |
32 | if self.0.is_null() { |
33 | return &[]; |
34 | } |
35 | |
36 | unsafe { std::slice::from_raw_parts(self.0, self.len()) } |
37 | } |
38 | |
39 | /// Create a `BSTR` from a slice of 16 bit characters (wchars). |
40 | pub fn from_wide(value: &[u16]) -> Result<Self> { |
41 | if value.is_empty() { |
42 | return Ok(Self::new()); |
43 | } |
44 | |
45 | let result = unsafe { Self(crate::imp::SysAllocStringLen(value.as_ptr(), value.len().try_into()?)) }; |
46 | |
47 | if result.is_empty() { |
48 | Err(crate::imp::E_OUTOFMEMORY.into()) |
49 | } else { |
50 | Ok(result) |
51 | } |
52 | } |
53 | |
54 | /// # Safety |
55 | #[doc (hidden)] |
56 | pub unsafe fn from_raw(raw: *const u16) -> Self { |
57 | Self(raw) |
58 | } |
59 | |
60 | /// # Safety |
61 | #[doc (hidden)] |
62 | pub fn into_raw(self) -> *const u16 { |
63 | unsafe { std::mem::transmute(self) } |
64 | } |
65 | } |
66 | |
67 | impl std::clone::Clone for BSTR { |
68 | fn clone(&self) -> Self { |
69 | Self::from_wide(self.as_wide()).unwrap() |
70 | } |
71 | } |
72 | |
73 | impl std::convert::From<&str> for BSTR { |
74 | fn from(value: &str) -> Self { |
75 | let value: std::vec::Vec<u16> = value.encode_utf16().collect(); |
76 | Self::from_wide(&value).unwrap() |
77 | } |
78 | } |
79 | |
80 | impl std::convert::From<std::string::String> for BSTR { |
81 | fn from(value: std::string::String) -> Self { |
82 | value.as_str().into() |
83 | } |
84 | } |
85 | |
86 | impl std::convert::From<&std::string::String> for BSTR { |
87 | fn from(value: &std::string::String) -> Self { |
88 | value.as_str().into() |
89 | } |
90 | } |
91 | |
92 | impl<'a> std::convert::TryFrom<&'a BSTR> for std::string::String { |
93 | type Error = std::string::FromUtf16Error; |
94 | |
95 | fn try_from(value: &BSTR) -> std::result::Result<Self, Self::Error> { |
96 | std::string::String::from_utf16(value.as_wide()) |
97 | } |
98 | } |
99 | |
100 | impl std::convert::TryFrom<BSTR> for std::string::String { |
101 | type Error = std::string::FromUtf16Error; |
102 | |
103 | fn try_from(value: BSTR) -> std::result::Result<Self, Self::Error> { |
104 | std::string::String::try_from(&value) |
105 | } |
106 | } |
107 | |
108 | impl std::default::Default for BSTR { |
109 | fn default() -> Self { |
110 | Self(std::ptr::null_mut()) |
111 | } |
112 | } |
113 | |
114 | impl std::fmt::Display for BSTR { |
115 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
116 | std::write!(f, " {}" , crate::Decode(|| std::char::decode_utf16(self.as_wide().iter().cloned()))) |
117 | } |
118 | } |
119 | |
120 | impl std::fmt::Debug for BSTR { |
121 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
122 | std::write!(f, " {}" , self) |
123 | } |
124 | } |
125 | |
126 | impl std::cmp::PartialEq for BSTR { |
127 | fn eq(&self, other: &Self) -> bool { |
128 | self.as_wide() == other.as_wide() |
129 | } |
130 | } |
131 | |
132 | impl std::cmp::Eq for BSTR {} |
133 | |
134 | impl std::cmp::PartialEq<BSTR> for &str { |
135 | fn eq(&self, other: &BSTR) -> bool { |
136 | other == self |
137 | } |
138 | } |
139 | |
140 | impl std::cmp::PartialEq<BSTR> for String { |
141 | fn eq(&self, other: &BSTR) -> bool { |
142 | other == self |
143 | } |
144 | } |
145 | |
146 | impl<T: AsRef<str> + ?Sized> std::cmp::PartialEq<T> for BSTR { |
147 | fn eq(&self, other: &T) -> bool { |
148 | self.as_wide().iter().copied().eq(other.as_ref().encode_utf16()) |
149 | } |
150 | } |
151 | |
152 | impl std::ops::Drop for BSTR { |
153 | fn drop(&mut self) { |
154 | if !self.0.is_null() { |
155 | unsafe { crate::imp::SysFreeString(self.0) } |
156 | } |
157 | } |
158 | } |
159 | |
160 | impl TypeKind for BSTR { |
161 | type TypeKind = ValueType; |
162 | } |
163 | |