1use crate::com_types::currency::ComCurrency;
4use crate::com_types::date::ComDate;
5use crate::com_types::decimal::ComDecimal;
6use crate::Variant::*;
7use crate::VariantType::*;
8use crate::{variant, ComBool, PtrWrapper, Variant, VariantType, VT_BYREF};
9use std::string::FromUtf16Error;
10
11use std::convert::Infallible;
12use std::mem::ManuallyDrop;
13use thiserror::Error;
14use windows::core::HRESULT;
15use windows::Win32::Foundation::VARIANT_BOOL;
16use windows::Win32::System::Variant::{VARENUM, VARIANT};
17
18#[derive(Debug, PartialEq, Eq, Error)]
19pub enum VariantConversionError {
20 #[error("An error occured while converting the COM String to a Rust string.")]
21 StringConversionError,
22 #[error("An unknown occured while converting the value of the Variant object.")]
23 GenericConversionError,
24 #[error("The specified variant type is known but not supported.")]
25 Unimplemented(VariantType),
26 #[error("A reference-only variant type was used without VT_BYREF.")]
27 InvalidDirect(VariantType),
28 #[error("An invalid variant type was used in conjunction with VT_BYREF.")]
29 InvalidReference(VariantType),
30 #[error("The specified type can only be used in a TYPEDESC structure.")]
31 TypeDescOnly(VariantType),
32 #[error("The specified variant type is unknown.")]
33 UnknownType(VARENUM),
34}
35
36impl From<Infallible> for VariantConversionError {
37 fn from(p: Infallible) -> Self {
38 match p {}
39 }
40}
41
42impl From<FromUtf16Error> for VariantConversionError {
43 fn from(_: FromUtf16Error) -> VariantConversionError {
44 VariantConversionError::StringConversionError
45 }
46}
47
48impl From<()> for VariantConversionError {
49 fn from(_: ()) -> VariantConversionError {
50 VariantConversionError::GenericConversionError
51 }
52}
53
54#[doc(hidden)]
55#[macro_export]
56macro_rules! types
57{
58 ( @vt $t: ident, $val:expr, $is_ref:expr, $vtype:ident => ($res:expr), / ) => {
61 if $is_ref { Err(VariantConversionError::InvalidReference($t)) }
62 else { $res.map(Variant::$vtype).map_err(Into::into) }
63 };
64
65 ( @vt $t: ident, $val:expr, $is_ref:expr, $vtype:ident, / ) => {
67 if $is_ref { Err(VariantConversionError::InvalidReference($t)) }
68 else { Ok(Variant::$vtype) }
69 };
70
71 ( @vt $t: ident, $val:expr, $is_ref:expr, /, $atype: ident => ($ares: expr) ) => {
74 if $is_ref { $ares.map(Variant::$atype).map_err(Into::into) }
75 else { Err(VariantConversionError::InvalidDirect($t)) }
76 };
77
78 ( @ref $val: expr, $atype: ident, $ares: ident ) => {
79 ($val.Anonymous.Anonymous.$ares).as_mut::<'static>().ok_or(()).map(Into::into).map(Variant::$atype).map_err(Into::into)
80 };
81
82 ( @ref $val: expr, $atype: ident, $ares: expr ) => {
83 $ares.map(Variant::$atype)
84 };
85
86 ( @vt $t: expr, $val:expr, $is_ref:expr, $vtype:ident => ($res:expr), $atype: ident => $ares: expr ) => {
87 if $is_ref { types!(@ref $val, $atype, $ares) } else { $res.map(Variant::$vtype) }
88 };
89
90 ( @vt $t: expr, $val:expr, $is_ref:expr, $vtype:ident => $res:ident, $atype: ident => $ares: ident ) => {
91 if $is_ref { types!(@ref $val, $atype, $ares) } else { Ok(Variant::$vtype($val.Anonymous.Anonymous.$res)) }
92 };
93
94 ( @vt $t: expr, $val:expr, $is_ref:expr, $vtype:ident => $res:ident $op:tt $opexpr:expr, $atype: ident => $ares: ident ) => {
95 if $is_ref { types!(@ref $val, $atype, $ares) } else { Ok(Variant::$vtype($val.Anonymous.Anonymous.$res $op $opexpr)) }
96 };
97
98 ($val:expr, $is_ref:expr, $t:expr, [$( $name:ident : ( $($tts:tt)* ) ),*], [ $( $($pat:ident)|+ => $expr:expr ),*], [ $([ $( $u:ident ),* ] => $err:ident),* ]) => {
99 match $t
100 {
101 Some(t) => match t
102 {
103 $($name => types!(@vt $name, $val, $is_ref, $($tts)*) ,)*
104 $($($pat => $expr ,)*)*
105 $($($u => Err(VariantConversionError::$err($u)),)*)*
106 },
107 None => Err(VariantConversionError::UnknownType($val.Anonymous.vt))
108 }
109 };
110}
111
112impl TryInto<Variant> for VARIANT {
113 type Error = VariantConversionError;
114
115 fn try_into(self) -> Result<Variant, VariantConversionError> {
116 unsafe {
117 let val = self.Anonymous;
118
119 let (unrefd, is_ref) = if val.Anonymous.vt.0 & VT_BYREF != 0 {
120 (val.Anonymous.vt.0 & !VT_BYREF, true)
121 } else {
122 (val.Anonymous.vt.0, false)
123 };
124
125 types!(val, is_ref, VariantType::n(unrefd), [
126 VT_EMPTY : (Empty, /),
127 VT_NULL : (Null, /),
128
129 VT_BOOL : (Bool => (Ok(val.Anonymous.Anonymous.boolVal.0 != 0)), BoolRef => (Ok(&mut *(val.Anonymous.Anonymous.pboolVal as *mut ComBool)))),
130
131 VT_I1 : (I8 => (Ok(val.Anonymous.Anonymous.cVal as i8)), I8Ref => (Ok(val.Anonymous.Anonymous.pcVal))),
132 VT_I2 : (I16 => iVal, I16Ref => piVal),
133 VT_I4 : (I32 => lVal, I32Ref => plVal),
134 VT_I8 : (I64 => llVal, I64Ref => pllVal),
135 VT_UI1 : (U8 => bVal, U8Ref => pbVal),
136 VT_UI2 : (U16 => uiVal, U16Ref => puiVal),
137 VT_UI4 : (U32 => ulVal, U32Ref => pulVal),
138 VT_UI8 : (U64 => ullVal, U64Ref => pullVal),
139 VT_INT : (I32 => lVal, I32Ref => plVal),
140 VT_UINT : (U32 => ulVal, U32Ref => pulVal),
141
142 VT_R4 : (F32 => fltVal, F32Ref => pfltVal),
143 VT_R8 : (F64 => dblVal, F64Ref => pdblVal),
144
145 VT_CY : (
146 Currency => (Ok(ComCurrency::from(val.Anonymous.Anonymous.cyVal).into())),
147 CurrencyRef => (Ok(<&mut ComCurrency>::from(val.Anonymous.Anonymous.pcyVal)))),
148
149 VT_DECIMAL : (
150 Decimal => (Ok(ComDecimal(val.decVal).into())),
151 DecimalRef => (Ok(<&mut ComDecimal>::from(val.Anonymous.Anonymous.pdecVal)))),
152
153 VT_DATE : (
154 Date => (Ok(ComDate(val.Anonymous.Anonymous.date).into())),
155 DateRef => (Ok(<&mut ComDate>::from(val.Anonymous.Anonymous.pdate)))),
156
157 VT_BSTR : (String => (Ok::<_, Infallible>(ManuallyDrop::into_inner(ManuallyDrop::into_inner(val.Anonymous).Anonymous.bstrVal))), /),
158
159 VT_DISPATCH : (Dispatch => (Ok::<_, Infallible>((*ManuallyDrop::into_inner(val.Anonymous).Anonymous.pdispVal).take())), /),
160 VT_UNKNOWN : (Unknown => (Ok::<_, Infallible>((*ManuallyDrop::into_inner(val.Anonymous).Anonymous.punkVal).take())), /),
161
162 VT_ERROR : (Error => (Ok(HRESULT(val.Anonymous.Anonymous.scode))), ErrorRef => (Ok((val.Anonymous.Anonymous.pscode as *mut HRESULT).as_mut::<'static>().unwrap()))),
163
164 VT_VARIANT : (/, VariantRef => (PtrWrapper::try_from(&val.Anonymous.Anonymous.pvarVal)))
165 ], [
166
167 ], [
168 [VT_RECORD] => Unimplemented,
169 [
170 VT_VOID, VT_HRESULT,
171 VT_SAFEARRAY, VT_CARRAY,
172 VT_USERDEFINED,
173 VT_LPSTR, VT_LPWSTR,
174 VT_PTR, VT_INT_PTR, VT_UINT_PTR
175 ] => TypeDescOnly
176 ])
177 }
178 }
179}
180
181impl TryInto<VARIANT> for Variant {
182 type Error = VariantConversionError;
183
184 fn try_into(self) -> Result<VARIANT, VariantConversionError> {
185 match self {
186 Empty => Ok(variant!(VT_EMPTY)),
187 Null => Ok(variant!(VT_NULL)),
188
189 Bool(b) => Ok(variant!(
190 VT_BOOL,
191 boolVal,
192 VARIANT_BOOL(ComBool::from(b) as i16)
193 )),
194 BoolRef(b) => Ok(variant!(
195 VT_BOOL,
196 pboolVal,
197 b as *mut ComBool as *mut VARIANT_BOOL
198 )),
199
200 I8(i) => Ok(variant!(VT_I1, cVal, i as u8)),
201 I8Ref(i) => Ok(variant!(VT_I1.byref(), pcVal, i)),
202 I16(i) => Ok(variant!(VT_I2, iVal, i)),
203 I16Ref(i) => Ok(variant!(VT_I2.byref(), piVal, i)),
204 I32(i) => Ok(variant!(VT_I4, lVal, i)),
205 I32Ref(i) => Ok(variant!(VT_I4.byref(), plVal, i)),
206 I64(i) => Ok(variant!(VT_I8, llVal, i)),
207 I64Ref(i) => Ok(variant!(VT_I8.byref(), pllVal, i)),
208
209 U8(i) => Ok(variant!(VT_UI1, bVal, i)),
210 U8Ref(i) => Ok(variant!(VT_UI1.byref(), pbVal, i)),
211 U16(i) => Ok(variant!(VT_UI2, uiVal, i)),
212 U16Ref(i) => Ok(variant!(VT_UI2.byref(), puiVal, i)),
213 U32(i) => Ok(variant!(VT_UI4, ulVal, i)),
214 U32Ref(i) => Ok(variant!(VT_UI4.byref(), pulVal, i)),
215 U64(i) => Ok(variant!(VT_UI8, ullVal, i)),
216 U64Ref(i) => Ok(variant!(VT_UI8.byref(), pullVal, i)),
217
218 F32(f) => Ok(variant!(VT_R4, fltVal, f)),
219 F32Ref(f) => Ok(variant!(VT_R4.byref(), pfltVal, f)),
220 F64(f) => Ok(variant!(VT_R8, dblVal, f)),
221 F64Ref(f) => Ok(variant!(VT_R8.byref(), pdblVal, f)),
222
223 Currency(d) => Ok(variant!(VT_CY, cyVal, ComCurrency::from(d).into())),
224 CurrencyRef(r) => Ok(variant!(VT_CY.byref(), pcyVal, r.as_mut_ptr())),
225
226 Decimal(d) => Ok(variant!(VT_DECIMAL, (decVal), ComDecimal::from(d).0)),
227 DecimalRef(d) => Ok(variant!(VT_DECIMAL.byref(), pdecVal, d.as_mut_ptr())),
228
229 Date(d) => Ok(variant!(VT_DATE, date, ComDate::from(d).0)),
230 DateRef(d) => Ok(variant!(VT_DATE.byref(), pdate, d.as_mut_ptr())),
231
232 String(s) => Ok(variant!(VT_BSTR, bstrVal, ManuallyDrop::new(s))),
233 StringRef(s) => Ok(variant!(VT_BSTR.byref(), pbstrVal, s)),
234
235 Dispatch(ptr) => Ok(variant!(VT_DISPATCH, pdispVal, ManuallyDrop::new(ptr))),
236 Unknown(ptr) => Ok(variant!(VT_UNKNOWN, punkVal, ManuallyDrop::new(ptr))),
237
238 Error(code) => Ok(variant!(VT_ERROR, scode, code.0)),
239 ErrorRef(code) => Ok(variant!(VT_ERROR.byref(), pscode, &mut code.0)),
240
241 VariantRef(ptr) => Ok(variant!(VT_VARIANT.byref(), pvarVal, ptr.0)),
242 }
244 }
245}