sapi_lite/stt/semantics/
value.rs1use std::ffi::{OsStr, OsString};
2use std::mem::ManuallyDrop;
3
4use windows as Windows;
5use Windows::core::{IntoParam, Param};
6use Windows::Win32::Foundation::PWSTR;
7use Windows::Win32::Media::Speech::{SPPHRASEPROPERTY, SPPROPERTYINFO};
8use Windows::Win32::System::Com::{VARIANT, VARIANT_0, VARIANT_0_0, VARIANT_0_0_0};
9use Windows::Win32::System::Ole::{VARENUM, VT_BOOL, VT_EMPTY, VT_I4, VT_R4, VT_R8};
10
11use crate::com_util::from_wide;
12
13use super::SemanticString;
14
15#[derive(Debug, PartialEq, Clone)]
17#[allow(missing_docs)]
18pub enum SemanticValue<S: SemanticString> {
19 Bool(bool),
20 Int(i32),
21 Float(f32),
22 Double(f64),
23 String(S),
24}
25
26impl<S: SemanticString> SemanticValue<S> {
27 pub fn into<T: SemanticString>(self) -> SemanticValue<T>
29 where
30 S: Into<T>,
31 {
32 match self {
33 Self::Bool(b) => SemanticValue::Bool(b),
34 Self::Int(i) => SemanticValue::Int(i),
35 Self::Float(f) => SemanticValue::Float(f),
36 Self::Double(d) => SemanticValue::Double(d),
37 Self::String(s) => SemanticValue::String(s.into()),
38 }
39 }
40
41 pub fn as_bool(&self) -> Option<&bool> {
43 if let Self::Bool(b) = self {
44 Some(b)
45 } else {
46 None
47 }
48 }
49
50 pub fn as_int(&self) -> Option<&i32> {
52 if let Self::Int(i) = self {
53 Some(i)
54 } else {
55 None
56 }
57 }
58
59 pub fn as_float(&self) -> Option<&f32> {
61 if let Self::Float(f) = self {
62 Some(f)
63 } else {
64 None
65 }
66 }
67
68 pub fn as_double(&self) -> Option<&f64> {
70 if let Self::Double(d) = self {
71 Some(d)
72 } else {
73 None
74 }
75 }
76
77 pub fn as_string(&self) -> Option<&S> {
79 if let Self::String(s) = self {
80 Some(s)
81 } else {
82 None
83 }
84 }
85
86 fn to_pwstr<'s>(&self) -> Param<'s, PWSTR> {
87 match self {
88 SemanticValue::String(s) => s.as_os_str().into_param(),
89 _ => Param::None,
90 }
91 }
92
93 fn variant_type(&self) -> u16 {
94 match self {
95 SemanticValue::Bool(_) => VT_BOOL,
96 SemanticValue::Int(_) => VT_I4,
97 SemanticValue::Float(_) => VT_R4,
98 SemanticValue::Double(_) => VT_R8,
99 SemanticValue::String(_) => VT_EMPTY,
100 }
101 .0 as _
102 }
103
104 fn to_variant_union(&self) -> VARIANT_0_0_0 {
105 match self {
106 SemanticValue::Bool(b) => VARIANT_0_0_0 {
107 boolVal: -(*b as i16),
110 },
111 SemanticValue::Int(i) => VARIANT_0_0_0 { lVal: *i },
112 SemanticValue::Float(f) => VARIANT_0_0_0 { fltVal: *f },
113 SemanticValue::Double(d) => VARIANT_0_0_0 { dblVal: *d },
114 SemanticValue::String(_) => Default::default(),
115 }
116 }
117}
118
119impl SemanticValue<OsString> {
120 pub(super) fn from_sapi(property: &SPPHRASEPROPERTY) -> Result<Self, VARENUM> {
121 if !property.pszValue.is_null() {
122 Ok(Self::String(
123 unsafe { from_wide(&property.pszValue) }.into(),
124 ))
125 } else {
126 let var_type = unsafe { property.vValue.Anonymous.Anonymous.vt };
127 let var_value = unsafe { &property.vValue.Anonymous.Anonymous.Anonymous };
128 match VARENUM(var_type as _) {
129 VT_BOOL => Ok(Self::Bool(unsafe { var_value.boolVal } != 0)),
130 VT_I4 => Ok(Self::Int(unsafe { var_value.lVal })),
131 VT_R4 => Ok(Self::Float(unsafe { var_value.fltVal })),
132 VT_R8 => Ok(Self::Double(unsafe { var_value.dblVal })),
133 vt @ _ => Err(vt),
134 }
135 }
136 }
137}
138
139impl<S: SemanticString> From<bool> for SemanticValue<S> {
140 fn from(source: bool) -> Self {
141 Self::Bool(source)
142 }
143}
144
145impl<S: SemanticString> From<i32> for SemanticValue<S> {
146 fn from(source: i32) -> Self {
147 Self::Int(source)
148 }
149}
150
151impl<S: SemanticString> From<f32> for SemanticValue<S> {
152 fn from(source: f32) -> Self {
153 Self::Float(source)
154 }
155}
156
157impl<S: SemanticString> From<f64> for SemanticValue<S> {
158 fn from(source: f64) -> Self {
159 Self::Double(source)
160 }
161}
162
163impl<F: SemanticString + Into<T>, T: SemanticString> From<F> for SemanticValue<T> {
164 fn from(source: F) -> Self {
165 Self::String(source.into())
166 }
167}
168
169impl<S: SemanticString> PartialEq<bool> for SemanticValue<S> {
170 fn eq(&self, other: &bool) -> bool {
171 self.as_bool().map(|value| value == other).unwrap_or(false)
172 }
173}
174
175impl<S: SemanticString> PartialEq<SemanticValue<S>> for bool {
176 fn eq(&self, other: &SemanticValue<S>) -> bool {
177 other.as_bool().map(|value| value == self).unwrap_or(false)
178 }
179}
180
181impl<S: SemanticString> PartialEq<i32> for SemanticValue<S> {
182 fn eq(&self, other: &i32) -> bool {
183 self.as_int().map(|value| value == other).unwrap_or(false)
184 }
185}
186
187impl<S: SemanticString> PartialEq<SemanticValue<S>> for i32 {
188 fn eq(&self, other: &SemanticValue<S>) -> bool {
189 other.as_int().map(|value| value == self).unwrap_or(false)
190 }
191}
192
193impl<S: SemanticString> PartialEq<f32> for SemanticValue<S> {
194 fn eq(&self, other: &f32) -> bool {
195 self.as_float().map(|value| value == other).unwrap_or(false)
196 }
197}
198
199impl<S: SemanticString> PartialEq<SemanticValue<S>> for f32 {
200 fn eq(&self, other: &SemanticValue<S>) -> bool {
201 other.as_float().map(|value| value == self).unwrap_or(false)
202 }
203}
204
205impl<S: SemanticString> PartialEq<f64> for SemanticValue<S> {
206 fn eq(&self, other: &f64) -> bool {
207 self.as_double()
208 .map(|value| value == other)
209 .unwrap_or(false)
210 }
211}
212
213impl<S: SemanticString> PartialEq<SemanticValue<S>> for f64 {
214 fn eq(&self, other: &SemanticValue<S>) -> bool {
215 other
216 .as_double()
217 .map(|value| value == self)
218 .unwrap_or(false)
219 }
220}
221
222impl<S: SemanticString> PartialEq<str> for SemanticValue<S> {
223 fn eq(&self, other: &str) -> bool {
224 self.as_string()
225 .map(|value| value.as_os_str() == other.as_os_str())
226 .unwrap_or(false)
227 }
228}
229
230impl<S: SemanticString> PartialEq<SemanticValue<S>> for str {
231 fn eq(&self, other: &SemanticValue<S>) -> bool {
232 other
233 .as_string()
234 .map(|value| value.as_os_str() == self.as_os_str())
235 .unwrap_or(false)
236 }
237}
238
239impl<S: SemanticString> PartialEq<&str> for SemanticValue<S> {
240 fn eq(&self, other: &&str) -> bool {
241 self.as_string()
242 .map(|value| value.as_os_str() == other.as_os_str())
243 .unwrap_or(false)
244 }
245}
246
247impl<S: SemanticString> PartialEq<SemanticValue<S>> for &str {
248 fn eq(&self, other: &SemanticValue<S>) -> bool {
249 other
250 .as_string()
251 .map(|value| value.as_os_str() == self.as_os_str())
252 .unwrap_or(false)
253 }
254}
255
256impl<S: SemanticString> PartialEq<OsStr> for SemanticValue<S> {
257 fn eq(&self, other: &OsStr) -> bool {
258 self.as_string()
259 .map(|value| value.as_os_str() == other)
260 .unwrap_or(false)
261 }
262}
263
264impl<S: SemanticString> PartialEq<SemanticValue<S>> for OsStr {
265 fn eq(&self, other: &SemanticValue<S>) -> bool {
266 other
267 .as_string()
268 .map(|value| value.as_os_str() == self)
269 .unwrap_or(false)
270 }
271}
272
273impl<S: SemanticString> PartialEq<&OsStr> for SemanticValue<S> {
274 fn eq(&self, other: &&OsStr) -> bool {
275 self.as_string()
276 .map(|value| value.as_os_str() == *other)
277 .unwrap_or(false)
278 }
279}
280
281impl<S: SemanticString> PartialEq<SemanticValue<S>> for &OsStr {
282 fn eq(&self, other: &SemanticValue<S>) -> bool {
283 other
284 .as_string()
285 .map(|value| value.as_os_str() == *self)
286 .unwrap_or(false)
287 }
288}
289
290pub(crate) struct SemanticProperty<'s> {
291 pub(crate) info: SPPROPERTYINFO,
292 _pwstr: Param<'s, PWSTR>,
293}
294
295impl<'s> SemanticProperty<'s> {
296 pub(crate) fn new<S: SemanticString>(value: &SemanticValue<S>) -> Self {
297 let pwstr = value.to_pwstr();
298 Self {
299 info: SPPROPERTYINFO {
300 pszValue: unsafe { pwstr.abi() },
301 vValue: VARIANT {
302 Anonymous: VARIANT_0 {
303 Anonymous: ManuallyDrop::new(VARIANT_0_0 {
304 vt: value.variant_type(),
305 Anonymous: value.to_variant_union(),
306 ..Default::default()
307 }),
308 },
309 },
310 ..Default::default()
311 },
312 _pwstr: pwstr,
313 }
314 }
315}