use std::marker::PhantomData;
use std::mem;
use std::ptr::null_mut;
use winapi::ctypes::c_void;
use winapi::shared::wtypes::{
BSTR,
CY,
DATE,
DECIMAL,
VARIANT_BOOL,
VT_ARRAY,
VT_BSTR,
VT_BOOL,
VT_BYREF,
VT_CY,
VT_DATE,
VT_DECIMAL,
VT_DISPATCH,
VT_EMPTY,
VT_ERROR,
VT_I1,
VT_I2,
VT_I4,
VT_I8,
VT_INT,
VT_NULL,
VT_R4,
VT_R8,
VT_UI1,
VT_UI2,
VT_UI4,
VT_UI8,
VT_UINT,
VT_UNKNOWN,
VT_VARIANT,
};
use winapi::shared::wtypesbase::SCODE;
use winapi::um::oaidl::{IDispatch, SAFEARRAY, __tagVARIANT, VARIANT, VARIANT_n3, VARIANT_n1};
use winapi::um::oleauto::VariantClear;
use winapi::um::unknwnbase::IUnknown;
use super::array::SafeArrayElement;
use super::bstr::U16String;
use super::errors::{ElementError, FromVariantError, IntoVariantError};
use super::ptr::Ptr;
use super::types::{ Currency, Date, DecWrapper, Int, SCode, TryConvert, UInt, VariantBool };
const VT_PUI1: u32 = VT_BYREF | VT_UI1;
const VT_PI2: u32 = VT_BYREF | VT_I2;
const VT_PI4: u32 = VT_BYREF | VT_I4;
const VT_PI8: u32 = VT_BYREF | VT_I8;
const VT_PUI8: u32 = VT_BYREF | VT_UI8;
const VT_PR4: u32 = VT_BYREF | VT_R4;
const VT_PR8: u32 = VT_BYREF | VT_R8;
const VT_PBOOL: u32 = VT_BYREF | VT_BOOL;
const VT_PERROR: u32 = VT_BYREF | VT_ERROR;
const VT_PCY: u32 = VT_BYREF | VT_CY;
const VT_PDATE: u32 = VT_BYREF | VT_DATE;
const VT_PBSTR: u32 = VT_BYREF | VT_BSTR;
const VT_PUNKNOWN: u32 = VT_BYREF | VT_UNKNOWN;
const VT_PDISPATCH: u32 = VT_BYREF | VT_DISPATCH;
const VT_PARRAY: u32 = VT_BYREF | VT_ARRAY;
const VT_PDECIMAL: u32 = VT_BYREF | VT_DECIMAL;
const VT_PI1: u32 = VT_BYREF | VT_I1;
const VT_PUI2: u32 = VT_BYREF | VT_UI2;
const VT_PUI4: u32 = VT_BYREF | VT_UI4;
const VT_PINT: u32 = VT_BYREF | VT_INT;
const VT_PUINT: u32 = VT_BYREF | VT_UINT;
mod private {
use super::*;
#[doc(hidden)]
pub(crate) trait Sealed {}
#[doc(hidden)]
pub trait VariantAccess: Sized {
#[doc(hidden)]
const VTYPE: u32;
#[doc(hidden)]
type Field;
#[doc(hidden)]
fn from_var(n1: &VARIANT_n1, n3: &VARIANT_n3) -> Self::Field;
#[doc(hidden)]
fn into_var(inner: Self::Field, n1: &mut VARIANT_n1, n3: &mut VARIANT_n3);
}
macro_rules! impl_conversions {
(@impl <$($life:lifetime)*> $t:ty, $f:ty, $vtype:ident, $member:ident, $member_mut:ident) => {
impl $(<$life>)* VariantAccess for $t {
const VTYPE: u32 = $vtype;
type Field = $f;
fn from_var(_n1: &VARIANT_n1, n3: &VARIANT_n3) -> Self::Field {
unsafe {*n3.$member()}
}
fn into_var(inner: Self::Field, _n1: &mut VARIANT_n1, n3: &mut VARIANT_n3) {
unsafe {
let n_ptr = n3.$member_mut();
*n_ptr = inner;
}
}
}
};
( < $($tl:lifetime,)* $tn:ident : $tb:ident > $t:ty, $field:ty, $vtype:ident, $member:ident, $member_mut:ident ) => {
impl<$($tl,)* $tn> VariantAccess for $(&$tl)* $t
where
$tn: $tb
{
const VTYPE: u32 = $vtype;
type Field = $field;
fn from_var(_n1: &VARIANT_n1, n3: &VARIANT_n3) -> Self::Field {
unsafe {*n3.$member()}
}
fn into_var(inner: Self::Field, _n1: &mut VARIANT_n1, n3: &mut VARIANT_n3) {
unsafe {
let n_ptr = n3.$member_mut();
*n_ptr = inner;
}
}
}
};
(Ptr<$field:ty>, $vtype:ident, $member:ident, $member_mut:ident) => {
impl VariantAccess for Ptr<$field>{
const VTYPE: u32 = $vtype;
type Field = Ptr<$field>;
fn from_var(_n1: &VARIANT_n1, n3: &VARIANT_n3) -> Self::Field {
unsafe {Ptr::with_checked(*n3.$member()).unwrap()}
}
fn into_var(inner: Self::Field, _n1: &mut VARIANT_n1, n3: &mut VARIANT_n3) {
unsafe {
let n_ptr = n3.$member_mut();
*n_ptr = inner.as_ptr();
}
}
}
};
(Box<$t:ty>, $vtype:ident, $member:ident, $member_mut:ident) => {
impl_conversions!(@impl <> Box<$t>, *mut $t, $vtype, $member, $member_mut);
impl TryConvert<Box<$t>, IntoVariantError> for *mut $t {
fn try_convert(b: Box<$t>) -> Result<Self, IntoVariantError> {
Ok(Box::into_raw(b))
}
}
impl TryConvert<*mut $t, FromVariantError> for Box<$t> {
fn try_convert(ptr: *mut $t) -> Result<Self, FromVariantError> {
if ptr.is_null() { return Err(FromVariantError::VariantPtrNull)}
Ok(Box::new(unsafe{*ptr}))
}
}
};
($interm:ty => $f:ty, $vtype:ident, $member:ident, $member_mut:ident) => {
impl_conversions!(@impl <> $interm, $f, $vtype, $member, $member_mut);
};
($t:ty, $vtype:ident, $member:ident, $member_mut:ident) => {
impl_conversions!(@impl <> $t, $t, $vtype, $member, $member_mut);
};
}
impl_conversions!(i64, VT_I8, llVal, llVal_mut);
impl_conversions!(i32, VT_I4, lVal, lVal_mut);
impl_conversions!(u8, VT_UI1, bVal, bVal_mut);
impl_conversions!(i16, VT_I2, iVal, iVal_mut);
impl_conversions!(f32, VT_R4, fltVal, fltVal_mut);
impl_conversions!(f64, VT_R8, dblVal, dblVal_mut);
impl_conversions!(VariantBool => VARIANT_BOOL, VT_BOOL, boolVal, boolVal_mut);
impl_conversions!(SCode => SCODE, VT_ERROR, scode, scode_mut);
impl_conversions!(Currency => CY, VT_CY, cyVal, cyVal_mut);
impl_conversions!(Date => DATE, VT_DATE, date, date_mut);
impl_conversions!(U16String => BSTR, VT_BSTR, bstrVal, bstrVal_mut);
impl_conversions!(Ptr<IUnknown>, VT_UNKNOWN, punkVal, punkVal_mut);
impl_conversions!(Ptr<IDispatch>, VT_DISPATCH, pdispVal, pdispVal_mut);
impl_conversions!(< S : SafeArrayElement> Vec<S>, *mut SAFEARRAY, VT_ARRAY, parray, parray_mut);
#[allow(single_use_lifetimes)]
impl_conversions!(<'s, S: SafeArrayElement> &'s [S], *mut SAFEARRAY, VT_ARRAY, parray, parray_mut);
impl_conversions!(Box<VariantBool> => *mut VARIANT_BOOL, VT_PBOOL, pboolVal, pboolVal_mut);
impl_conversions!(Box<u8>, VT_PUI1, pbVal, pbVal_mut);
impl_conversions!(Box<i16>, VT_PI2, piVal, piVal_mut);
impl_conversions!(Box<i32>, VT_PI4, plVal, plVal_mut);
impl_conversions!(Box<i64>, VT_PI8, pllVal, pllVal_mut);
impl_conversions!(Box<f32>, VT_PR4, pfltVal, pfltVal_mut);
impl_conversions!(Box<f64>, VT_PR8, pdblVal, pdblVal_mut);
impl_conversions!(Box<SCode> => *mut SCODE, VT_PERROR, pscode, pscode_mut);
impl_conversions!(Box<Currency> => *mut CY, VT_PCY, pcyVal, pcyVal_mut);
impl_conversions!(Box<Date> => *mut DATE, VT_PDATE, pdate, pdate_mut);
impl_conversions!(Box<U16String> => *mut BSTR, VT_PBSTR, pbstrVal, pbstrVal_mut);
impl_conversions!(Box<Ptr<IUnknown>> => *mut *mut IUnknown, VT_PUNKNOWN, ppunkVal, ppunkVal_mut);
impl_conversions!(Box<Ptr<IDispatch>> => *mut *mut IDispatch, VT_PDISPATCH, ppdispVal, ppdispVal_mut);
impl_conversions!(< S : SafeArrayElement> Box<Vec<S>>, *mut *mut SAFEARRAY, VT_PARRAY, pparray, pparray_mut);
impl_conversions!(<'s, S: SafeArrayElement> Box<&'s [S]>, *mut *mut SAFEARRAY, VT_PARRAY, pparray, pparray_mut);
impl<D, T> VariantAccess for Variant<D, T>
where
D: VariantExt<T>
{
const VTYPE: u32 = VT_VARIANT;
type Field = Ptr<VARIANT>;
fn from_var(_n1: &VARIANT_n1, n3: &VARIANT_n3) -> Self::Field {
unsafe {Ptr::with_checked(*n3.pvarVal()).unwrap()}
}
fn into_var(inner: Self::Field, _n1: &mut VARIANT_n1, n3: &mut VARIANT_n3) {
unsafe {
let n_ptr = n3.pvarVal_mut();
*n_ptr = inner.as_ptr();
}
}
}
impl_conversions!(Ptr<c_void>, VT_BYREF, byref, byref_mut);
impl_conversions!(i8, VT_I1, cVal, cVal_mut);
impl_conversions!(u16, VT_UI2, uiVal, uiVal_mut);
impl_conversions!(u32, VT_UI4, ulVal, ulVal_mut);
impl_conversions!(u64, VT_UI8, ullVal, ullVal_mut);
impl_conversions!(Int => i32, VT_INT, intVal, intVal_mut);
impl_conversions!(UInt => u32, VT_UINT, uintVal, uintVal_mut);
impl_conversions!(Box<DecWrapper> => *mut DECIMAL, VT_PDECIMAL, pdecVal, pdecVal_mut);
impl_conversions!(Box<i8>, VT_PI1, pcVal, pcVal_mut);
impl_conversions!(Box<u16>, VT_PUI2, puiVal, puiVal_mut);
impl_conversions!(Box<u32>, VT_PUI4, pulVal, pulVal_mut);
impl_conversions!(Box<u64>, VT_PUI8, pullVal, pullVal_mut);
impl_conversions!(Box<Int> => *mut i32, VT_PINT, pintVal, pintVal_mut);
impl_conversions!(Box<UInt> => *mut u32, VT_PUINT, puintVal, puintVal_mut);
impl VariantAccess for DecWrapper {
const VTYPE: u32 = VT_DECIMAL;
type Field = DECIMAL;
fn from_var(n1: &VARIANT_n1, _n3: &VARIANT_n3) -> Self::Field {
unsafe {*n1.decVal()}
}
fn into_var(inner: Self::Field, n1: &mut VARIANT_n1, _n3: &mut VARIANT_n3) {
unsafe {
let n_ptr = n1.decVal_mut();
*n_ptr = inner;
}
}
}
impl VariantAccess for VtEmpty {
const VTYPE: u32 = VT_EMPTY;
type Field = ();
fn from_var(_n1: &VARIANT_n1, _n3: &VARIANT_n3) -> Self::Field {
()
}
fn into_var(_inner: Self::Field, _n1: &mut VARIANT_n1, _n3: &mut VARIANT_n3)
{}
}
impl VariantAccess for VtNull {
const VTYPE: u32 = VT_NULL;
type Field = ();
fn from_var(_n1: &VARIANT_n1, _n3: &VARIANT_n3) -> Self::Field {
()
}
fn into_var(_inner: Self::Field, _n1: &mut VARIANT_n1, _n3: &mut VARIANT_n3)
{}
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Variant<D, T>
where
D: VariantExt<T>
{
inner: D,
_marker: PhantomData<T>
}
impl<D, T> Variant<D, T>
where
D: VariantExt<T>
{
pub fn wrap(d: D) -> Self {
Variant{
inner: d,
_marker: PhantomData
}
}
pub fn unwrap(self) -> D {
self.inner
}
}
impl<D, T> TryConvert<Ptr<VARIANT>, FromVariantError> for Variant<D, T>
where
D: VariantExt<T>
{
fn try_convert(ptr: Ptr<VARIANT>) -> Result<Self, FromVariantError> {
Ok(Variant::wrap(VariantExt::<T>::from_variant(ptr)?))
}
}
impl<D, T> TryConvert<Variant<D, T>, IntoVariantError> for Ptr<VARIANT>
where
D: VariantExt<T>
{
fn try_convert(v: Variant<D, T>) -> Result<Self, IntoVariantError> {
let v = v.unwrap();
Ok(VariantExt::<T>::into_variant(v)?)
}
}
impl<D, T> TryConvert<Variant<D, T>, ElementError> for Ptr<VARIANT>
where
D: VariantExt<T>
{
fn try_convert(v: Variant<D, T>) -> Result<Self, ElementError> {
let v = v.unwrap();
Ok(VariantExt::<T>::into_variant(v)?)
}
}
impl<D, T> TryConvert<Ptr<VARIANT> , ElementError> for Variant<D, T>
where
D: VariantExt<T>
{
fn try_convert(ptr: Ptr<VARIANT> ) -> Result<Self, ElementError> {
Ok(Variant::wrap(VariantExt::<T>::from_variant(ptr)?))
}
}
struct VariantDestructor {
inner: *mut VARIANT,
_marker: PhantomData<VARIANT>
}
impl VariantDestructor {
fn new(p: *mut VARIANT) -> VariantDestructor {
VariantDestructor {
inner: p,
_marker: PhantomData
}
}
}
impl Drop for VariantDestructor {
fn drop(&mut self) {
if self.inner.is_null() {
return;
}
unsafe { VariantClear(self.inner)};
unsafe { mem::drop(*self.inner);}
self.inner = null_mut();
}
}
pub trait VariantExt<B>: Sized {
const VARTYPE: u32;
fn from_variant(var: Ptr<VARIANT>) -> Result<Self, FromVariantError>;
fn into_variant(value: Self) -> Result<Ptr<VARIANT>, IntoVariantError>;
}
impl<OutTy, InTy> VariantExt<InTy> for OutTy
where
OutTy: TryConvert<InTy, FromVariantError> + self::private::VariantAccess<Field=InTy>,
InTy: TryConvert<OutTy, IntoVariantError>
{
const VARTYPE: u32 = OutTy::VTYPE;
fn from_variant(pvar: Ptr<VARIANT>) -> Result<Self, FromVariantError> {
let var = pvar.as_ptr();
let _var_d = VariantDestructor::new(var);
let mut n1 = unsafe {(*var).n1};
let n3 = unsafe {n1.n2_mut().n3};
let inner = OutTy::from_var(&n1, &n3);
Ok(<OutTy as TryConvert<InTy, FromVariantError>>::try_convert(inner)?)
}
fn into_variant(value: OutTy) -> Result<Ptr<VARIANT>, IntoVariantError> {
let mut n3: VARIANT_n3 = unsafe {mem::zeroed()};
let mut n1: VARIANT_n1 = unsafe {mem::zeroed()};
OutTy::into_var(InTy::try_convert(value)?, &mut n1, &mut n3);
if OutTy::VARTYPE != VT_DECIMAL {
let tv = __tagVARIANT { vt: OutTy::VARTYPE as u16,
wReserved1: 0,
wReserved2: 0,
wReserved3: 0,
n3: n3};
unsafe {
let n_ptr = n1.n2_mut();
*n_ptr = tv;
};
}
let var = Box::new(VARIANT{ n1: n1 });
Ok(Ptr::with_checked(Box::into_raw(var)).unwrap())
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct VtEmpty;
impl TryConvert<(), FromVariantError> for VtEmpty {
fn try_convert(_e: ()) -> Result<Self, FromVariantError> {
Ok(VtEmpty)
}
}
impl TryConvert<VtEmpty, IntoVariantError> for () {
fn try_convert(_e: VtEmpty) -> Result<Self, IntoVariantError> {
Ok(())
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct VtNull;
impl TryConvert<(), FromVariantError> for VtNull {
fn try_convert(_e: ()) -> Result<Self, FromVariantError> {
Ok(VtNull)
}
}
impl TryConvert<VtNull, IntoVariantError> for () {
fn try_convert(_e: VtNull) -> Result<Self, IntoVariantError> {
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
use rust_decimal::Decimal;
macro_rules! validate_variant {
(@impl $t:ty, $val:expr, $vt:expr) => {
let v = $val;
let var: Ptr<VARIANT> = VariantExt::<_>::into_variant(v.clone()).unwrap();
assert!(!var.as_ptr().is_null());
unsafe {
let pvar = var.as_ptr();
let n1 = (*pvar).n1;
let tv: &__tagVARIANT = n1.n2();
assert_eq!(tv.vt as u32, $vt);
};
let var: $t = VariantExt::<_>::from_variant(var).unwrap();
assert_eq!(v, var);
};
(Box<$t:ty>, $val:expr, $vt:expr) => {
validate_variant!(@impl Box<$t>, $val, $vt);
};
($b:ident, $val:expr, $vt:expr) => {
validate_variant!(@impl $b, $val, $vt);
};
}
#[test]
fn test_i64() {
validate_variant!(i64, 1337i64, VT_I8);
}
#[test]
fn test_i32() {
validate_variant!(i32, 1337i32, VT_I4);
}
#[test]
fn test_u8() {
validate_variant!(u8, 137u8, VT_UI1);
}
#[test]
fn test_i16() {
validate_variant!(i16, 1337i16, VT_I2);
}
#[test]
fn test_f32() {
validate_variant!(f32, 1337.9f32, VT_R4);
}
#[test]
fn test_f64() {
validate_variant!(f64, 1337.9f64, VT_R8);
}
#[test]
fn test_bool_t() {
validate_variant!(VariantBool, VariantBool::from(true), VT_BOOL);
}
#[test]
fn test_bool_f() {
validate_variant!(VariantBool, VariantBool::from(false), VT_BOOL);
}
#[test]
fn test_scode() {
validate_variant!(SCode, SCode::from(137), VT_ERROR);
}
#[test]
fn test_cy() {
validate_variant!(Currency, Currency::from(137), VT_CY);
}
#[test]
fn test_date() {
validate_variant!(Date, Date::from(137.7), VT_DATE);
}
#[test]
fn test_str() {
validate_variant!(U16String, U16String::from_str("testing abc1267 ?Ťũřǐꝥꞔ"), VT_BSTR);
}
#[test]
fn test_box_u8() {
type Bu8 = Box<u8>;
validate_variant!(Bu8, Box::new(139), VT_PUI1);
}
#[test]
fn test_box_i16() {
type Bi16 = Box<i16>;
validate_variant!(Bi16, Box::new(139), VT_PI2);
}
#[test]
fn test_box_i32() {
type Bi32 = Box<i32>;
validate_variant!(Bi32, Box::new(139), VT_PI4);
}
#[test]
fn test_box_i64() {
type Bi64 = Box<i64>;
validate_variant!(Bi64, Box::new(139), VT_PI8);
}
#[test]
fn test_box_f32() {
type Bf32 = Box<f32>;
validate_variant!(Bf32, Box::new(1337.9f32), VT_PR4);
}
#[test]
fn test_box_f64() {
validate_variant!(Box<f64>, Box::new(1337.9f64), VT_PR8);
}
#[test]
fn test_box_bool() {
type BVb = Box<VariantBool>;
validate_variant!(BVb, Box::new(VariantBool::from(true)), VT_PBOOL);
}
#[test]
fn test_box_scode() {
type BSCode = Box<SCode>;
validate_variant!(BSCode, Box::new(SCode::from(-50)), VT_PERROR);
}
#[test]
fn test_box_cy() {
type BCy = Box<Currency>;
validate_variant!(BCy, Box::new(Currency::from(137)), VT_PCY);
}
#[test]
fn test_box_date() {
type BDate = Box<Date>;
validate_variant!(BDate, Box::new(Date::from(-10.333f64)), VT_PDATE);
}
#[test]
fn test_i8() {
validate_variant!(i8, -119i8, VT_I1);
}
#[test]
fn test_u16() {
validate_variant!(u16, 119u16, VT_UI2);
}
#[test]
fn test_u32() {
validate_variant!(u32, 11976u32, VT_UI4);
}
#[test]
fn test_u64() {
validate_variant!(u64, 11976u64, VT_UI8);
}
#[test]
fn int_wrapper() {
validate_variant!(Int, Int::from(13875), VT_INT);
}
#[test]
fn uint_wrapper() {
validate_variant!(UInt, UInt::from(13875), VT_UINT);
}
#[test]
fn test_box_i8() {
type Bi8 = Box<i8>;
validate_variant!(Bi8, Box::new(-119i8), VT_PI1);
}
#[test]
fn test_box_u16() {
type Bu16 = Box<u16>;
validate_variant!(Bu16, Box::new(119u16), VT_PUI2);
}
#[test]
fn test_box_u32() {
type Bu32 = Box<u32>;
validate_variant!(Bu32, Box::new(11976u32), VT_PUI4);
}
#[test]
fn test_box_u64() {
validate_variant!(Box<u64>, Box::new(11976u64), VT_PUI8);
}
#[test]
fn decimal() {
validate_variant!(DecWrapper, DecWrapper::from(Decimal::new(2,2)), 0);
}
#[test]
fn variant() {
let b = 156u8;
let c = Variant::wrap(b);
let v = VariantExt::<_>::into_variant(c).unwrap();
let v: Variant<u8, u8> = VariantExt::<_>::from_variant(v).unwrap();
let d = v.unwrap();
assert_eq!(d, b);
}
#[test]
fn empty() {
validate_variant!(VtEmpty, VtEmpty, VT_EMPTY);
}
#[test]
fn null() {
validate_variant!(VtNull, VtNull, VT_NULL);
}
#[test]
fn test_send() {
fn assert_send<T: Send>() {}
assert_send::<Variant<i64, i64>>();
}
#[test]
fn test_sync() {
fn assert_sync<T: Sync>() {}
assert_sync::<Variant<i64, i64>>();
}
}