1use crate::com_types::currency::{ComCurrency, Currency};
4use crate::com_types::date::ComDate;
5use crate::com_types::decimal::ComDecimal;
6use 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 }
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}