variant_rs/
variant.rs

1//! Rust wrapper for the [`VARIANT`] type
2
3use crate::com_types::currency::{ComCurrency, Currency};
4use crate::com_types::date::ComDate;
5use crate::com_types::decimal::ComDecimal;
6//use crate::com_types::string::ComString;
7use crate::{ComBool, PtrWrapper};
8use chrono::NaiveDateTime;
9use enumn::N;
10use rust_decimal::Decimal;
11
12use paste::paste;
13use windows::core::IUnknown;
14use windows::core::HRESULT;
15use windows::core::{BSTR, PSTR};
16use windows::Win32::System::Com::IDispatch;
17use windows::Win32::System::Variant::VARIANT;
18
19macro_rules! variant_enum {
20    (@impl $name:ident) => {};
21
22    (@impl $name:ident (&'static $($type:tt)+)) => {};
23
24    (@impl $name:ident (@@ $type:ty)) => {};
25
26    (@impl $name:ident (Option<$type:ty>)) => {
27        impl ToVariant for $type {
28            fn to_variant(self) -> Variant {
29                Variant::$name(Some(self))
30            }
31        }
32
33        variant_enum!(@impl @opt $name (Option<$type>));
34    };
35
36    (@impl $(@opt)? $name:ident ($type:ty)) => {
37        impl ToVariant for $type {
38            fn to_variant(self) -> Variant {
39                Variant::$name(self)
40            }
41        }
42    };
43
44    (@match $self:ident, $name:ident, $type:ty) => {
45        match $self {
46            Self::$name(v) => Ok(v),
47            _ => Err($self),
48        }
49    };
50
51    (@match $self:ident, $name:ident, ) => {
52        match $self {
53            Self::$name => Ok(()),
54            _ => Err($self),
55        }
56    };
57
58    (@enum $($name:ident $(( $(@@)? $( $type:ty )+ ) )?),* $(,)?) => {
59        #[derive(Debug, PartialEq)]
60        #[allow(clippy::enum_variant_names)]
61        pub enum Variant {
62            $($name $(($($type)+))?),*
63        }
64
65        paste! {
66            #[allow(unused_parens)]
67            impl Variant {
68                $(
69                    pub fn [< try_ $name:lower >](self) -> Result<( $($( $type )+)? ), Variant> {
70                        variant_enum!(@match self, $name, $($( $type )+)?)
71                    }
72
73                    pub fn [< expect_ $name:lower >](self) -> ( $($( $type )+)? ) {
74                        match self.[< try_ $name:lower >]() {
75                            Ok(v) => v,
76                            Err(self_) => panic!("Expected variant type {} but got {:?}", stringify!($name), self_),
77                        }
78                    }
79                )*
80            }
81        }
82    };
83
84    ($($name:ident $(( $($type:tt)+ ) )?),* $(,)?) => {
85        variant_enum!{@enum $($name $(( $($type)+ ))?),*}
86
87        $(variant_enum!{@impl $name $(($($type)+) )?})*
88    };
89}
90
91variant_enum! {
92    Empty,
93    Null,
94
95    Bool(bool),
96    BoolRef(&'static mut ComBool),
97
98    I8(i8),
99    I8Ref(PSTR),
100    I16(i16),
101    I16Ref(&'static mut i16),
102    I32(i32),
103    I32Ref(&'static mut i32),
104    I64(i64),
105    I64Ref(&'static mut i64),
106
107    U8(u8),
108    U8Ref(&'static mut u8),
109    U16(u16),
110    U16Ref(&'static mut u16),
111    U32(u32),
112    U32Ref(&'static mut u32),
113    U64(u64),
114    U64Ref(&'static mut u64),
115
116    F32(f32),
117    F32Ref(&'static mut f32),
118    F64(f64),
119    F64Ref(&'static mut f64),
120
121    Currency(Currency),
122    CurrencyRef(&'static mut ComCurrency),
123
124    Decimal(Decimal),
125    DecimalRef(&'static mut ComDecimal),
126
127    Date(NaiveDateTime),
128    DateRef(&'static mut ComDate),
129
130    String(BSTR),
131    StringRef(&'static mut BSTR),
132
133    Dispatch(Option<IDispatch>),
134    Unknown(Option<IUnknown>),
135
136    Error(@@ HRESULT),
137    ErrorRef(&'static mut HRESULT),
138
139    VariantRef(PtrWrapper<VARIANT>),
140
141    //Record(),
142}
143
144impl Clone for Variant {
145    fn clone(&self) -> Self {
146        use Variant::*;
147        match self {
148            BoolRef(_) | I8Ref(_) | I16Ref(_) | I32Ref(_) | I64Ref(_) | U8Ref(_) | U16Ref(_)
149            | U32Ref(_) | U64Ref(_) | F32Ref(_) | F64Ref(_) | CurrencyRef(_) | DecimalRef(_)
150            | DateRef(_) | StringRef(_) | ErrorRef(_) | VariantRef(_) => {
151                panic!("Cannot clone a reference variant")
152            }
153
154            Empty => Empty,
155            Null => Null,
156            Bool(x) => Bool(*x),
157            I8(x) => I8(*x),
158            I16(x) => I16(*x),
159            I32(x) => I32(*x),
160            I64(x) => I64(*x),
161            U8(x) => U8(*x),
162            U16(x) => U16(*x),
163            U32(x) => U32(*x),
164            U64(x) => U64(*x),
165            F32(x) => F32(*x),
166            F64(x) => F64(*x),
167            Currency(x) => Currency(*x),
168            Decimal(x) => Decimal(*x),
169            Date(x) => Date(*x),
170            String(x) => String(x.clone()),
171            Dispatch(x) => Dispatch(x.clone()),
172            Unknown(x) => Unknown(x.clone()),
173            Error(x) => Error(*x),
174        }
175    }
176}
177
178pub trait ToVariant {
179    fn to_variant(self) -> Variant;
180}
181
182impl ToVariant for () {
183    fn to_variant(self) -> Variant {
184        Variant::Null
185    }
186}
187
188impl ToVariant for &str {
189    fn to_variant(self) -> Variant {
190        Variant::String(BSTR::from(self))
191    }
192}
193
194impl ToVariant for String {
195    fn to_variant(self) -> Variant {
196        Variant::String(BSTR::from(self))
197    }
198}
199
200impl<T: Clone + ToVariant> ToVariant for &T {
201    fn to_variant(self) -> Variant {
202        self.clone().to_variant()
203    }
204}
205
206impl<T: ToVariant> From<T> for Variant {
207    fn from(t: T) -> Self {
208        t.to_variant()
209    }
210}
211
212#[derive(N, Debug, PartialEq, Eq, Copy, Clone)]
213#[allow(non_camel_case_types)]
214pub enum VariantType {
215    VT_EMPTY = 0,
216    VT_NULL = 1,
217    VT_I2 = 2,
218    VT_I4 = 3,
219    VT_R4 = 4,
220    VT_R8 = 5,
221    VT_CY = 6,
222    VT_DATE = 7,
223    VT_BSTR = 8,
224    VT_DISPATCH = 9,
225    VT_ERROR = 10,
226    VT_BOOL = 11,
227    VT_VARIANT = 12,
228    VT_UNKNOWN = 13,
229    VT_DECIMAL = 14,
230    VT_I1 = 16,
231    VT_UI1 = 17,
232    VT_UI2 = 18,
233    VT_UI4 = 19,
234    VT_I8 = 20,
235    VT_UI8 = 21,
236    VT_INT = 22,
237    VT_UINT = 23,
238    VT_VOID = 24,
239    VT_HRESULT = 25,
240    VT_PTR = 26,
241    VT_SAFEARRAY = 27,
242    VT_CARRAY = 28,
243    VT_USERDEFINED = 29,
244    VT_LPSTR = 30,
245    VT_LPWSTR = 31,
246    VT_RECORD = 36,
247    VT_INT_PTR = 37,
248    VT_UINT_PTR = 38,
249}
250
251pub const VT_BYREF: u16 = 16384;
252
253impl VariantType {
254    pub fn byref(self) -> u16 {
255        self as u16 | VT_BYREF
256    }
257}