sapi_lite/stt/semantics/
value.rs

1use 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/// A value that forms part of the semantic information for a recognized phrase.
16#[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    /// Converts the value from one generic type into a compatible generic type.
28    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    /// Borrows the underlying value, if this is a `SemanticValue::Bool`.
42    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    /// Borrows the underlying value, if this is a `SemanticValue::Int`.
51    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    /// Borrows the underlying value, if this is a `SemanticValue::Float`.
60    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    /// Borrows the underlying value, if this is a `SemanticValue::Double`.
69    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    /// Borrows the underlying value, if this is a `SemanticValue::String`.
78    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                // per https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant
108                // 0 is false and 0xffff is true
109                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}