variant_rs/
convert.rs

1//! Conversion between native [`VARIANT`] and Rust [`Variant`]
2
3use 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    // Direct-only type; custom expression
59    // VT_DISPATCH : (Dispatch => (...), /),
60    ( @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_EMPTY : (Empty, /)
66    ( @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    // Reference-only type, custom expression
72    // VT_VARIANT : (/, VariantRef => ...)
73    ( @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            //_ => Err(VariantConversionError::GenericConversionError),
243        }
244    }
245}