use std::marker::PhantomData;
use std::mem;
use std::ptr::{drop_in_place, null_mut};
use super::bstr::U16String;
use winapi::ctypes::{c_long, c_void};
use winapi::shared::minwindef::{UINT, ULONG,};
use winapi::shared::ntdef::HRESULT;
use winapi::shared::wtypes::{
BSTR,
CY,
DATE,
DECIMAL,
VARTYPE,
VARIANT_BOOL,
VT_BSTR,
VT_BOOL,
VT_CY,
VT_DATE,
VT_DECIMAL,
VT_DISPATCH,
VT_ERROR,
VT_I1,
VT_I2,
VT_I4,
VT_INT,
VT_R4,
VT_R8,
VT_UI1,
VT_UI2,
VT_UI4,
VT_UINT,
VT_UNKNOWN,
VT_VARIANT,
};
use winapi::shared::wtypesbase::SCODE;
use winapi::um::oaidl::{IDispatch, LPSAFEARRAY, LPSAFEARRAYBOUND, SAFEARRAY, SAFEARRAYBOUND, VARIANT};
use winapi::um::unknwnbase::IUnknown;
use super::errors::{
ElementError,
FromSafeArrayError,
FromSafeArrElemError,
IntoSafeArrayError,
IntoSafeArrElemError,
SafeArrayError
};
use super::ptr::Ptr;
use super::types::{Currency, Date, DecWrapper, Int, SCode, TryConvert, UInt, VariantBool};
use super::variant::{Variant, VariantExt};
macro_rules! check_and_throw {
($hr:ident, $success:expr, $fail:expr) => {
match $hr {
0 => $success,
_ => $fail
}
};
}
struct EmptyMemoryDestructor<T> {
pub(crate) inner: *mut T,
_marker: PhantomData<T>
}
impl<T> EmptyMemoryDestructor<T> {
fn new(t: *mut T) -> EmptyMemoryDestructor<T> {
EmptyMemoryDestructor{
inner: t,
_marker: PhantomData
}
}
}
impl<T> Drop for EmptyMemoryDestructor<T> {
fn drop(&mut self) {
if self.inner.is_null() {
return;
}
unsafe {
drop_in_place(self.inner);
}
self.inner = null_mut();
}
}
pub trait SafeArrayElement
where
Self: Sized
{
#[doc(hidden)]
const SFTYPE: u32;
#[doc(hidden)]
type Element: TryConvert<Self, ElementError>;
#[doc(hidden)]
fn from_safearray(psa: *mut SAFEARRAY, ix: i32) -> Result<Self::Element, ElementError> {
let mut def_val: Self::Element = unsafe {mem::zeroed()};
let mut empty = EmptyMemoryDestructor::new(&mut def_val);
#[allow(trivial_casts)]
let hr = unsafe {SafeArrayGetElement(psa, &ix, &mut def_val as *mut _ as *mut c_void)};
match hr {
0 => {
empty.inner = null_mut();
Ok(def_val)
},
_ => {
Err(ElementError::from(FromSafeArrElemError::GetElementFailed{hr: hr}))
}
}
}
#[doc(hidden)]
fn into_safearray(self, psa: *mut SAFEARRAY, ix: i32) -> Result<(), ElementError> {
let mut slf = Self::Element::try_convert(self)?;
#[allow(trivial_casts)]
let hr = unsafe { SafeArrayPutElement(psa, &ix, &mut slf as *mut _ as *mut c_void)};
match hr {
0 => Ok(()),
_ => Err(ElementError::from(IntoSafeArrElemError::PutElementFailed{hr: hr}))
}
}
}
macro_rules! impl_safe_arr_elem {
($(#[$attrs:meta])* $t:ty => $element:ty, $vtype:ident) => {
$(#[$attrs])*
impl SafeArrayElement for $t {
const SFTYPE: u32 = $vtype;
type Element = $element;
}
};
($(#[$attrs:meta])* $t:ty, $vtype:ident) => {
$(#[$attrs])*
impl SafeArrayElement for $t {
const SFTYPE: u32 = $vtype;
type Element = $t;
}
};
}
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for `i16`. This allows it to be converted into SAFEARRAY with vt = `VT_I2`."] i16, VT_I2);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for `i32`. This allows it to be converted into SAFEARRAY with vt = `VT_I4`."] i32, VT_I4);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for `f32`. This allows it to be converted into SAFEARRAY with vt = `VT_R4`."] f32, VT_R4);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for `f64`. This allows it to be converted into SAFEARRAY with vt = `VT_R8`."] f64, VT_R8);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for [`Currency`]:struct.Currency.html . This allows it to be converted into SAFEARRAY with vt = `VT_CY`."] Currency => CY, VT_CY);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for ['Date']: struct.Date.html. This allows it to be converted into SAFEARRAY with vt = `VT_DATE`."] Date => DATE, VT_DATE);
impl SafeArrayElement for U16String {
const SFTYPE: u32 = VT_BSTR;
type Element = BSTR;
fn into_safearray(self, psa: *mut SAFEARRAY, ix: i32) -> Result<(), ElementError> {
let slf = <BSTR as TryConvert<U16String, ElementError>>::try_convert(self)?;
let hr = unsafe { SafeArrayPutElement(psa, &ix, slf as *mut c_void)};
match hr {
0 => Ok(()),
_ => Err(ElementError::from(IntoSafeArrElemError::PutElementFailed{hr: hr}))
}
}
}
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for ['SCode']. This allows it to be converted into SAFEARRAY with vt = `VT_ERROR`."]SCode => SCODE, VT_ERROR);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for ['VariantBool']. This allows it to be converted into SAFEARRAY with vt = `VT_BOOL`."]VariantBool => VARIANT_BOOL, VT_BOOL);
impl<D, T> SafeArrayElement for Variant<D, T>
where
D: VariantExt<T>
{
const SFTYPE: u32 = VT_VARIANT;
type Element = Ptr<VARIANT>;
#[doc(hidden)]
fn from_safearray(psa: *mut SAFEARRAY, ix: i32) -> Result<Self::Element, ElementError> {
let mut def_val: VARIANT = unsafe {mem::zeroed()};
let mut empty = EmptyMemoryDestructor::new(&mut def_val);
#[allow(trivial_casts)]
let hr = unsafe {SafeArrayGetElement(psa, &ix, &mut def_val as *mut _ as *mut c_void)};
match hr {
0 => {
empty.inner = null_mut();
Ok(Ptr::with_checked(Box::into_raw(Box::new(def_val))).unwrap())
},
_ => {
Err(ElementError::from(FromSafeArrElemError::GetElementFailed{hr: hr}))
}
}
}
#[doc(hidden)]
fn into_safearray(self, psa: *mut SAFEARRAY, ix: i32) -> Result<(), ElementError> {
let slf = <Ptr<VARIANT> as TryConvert<Variant<D, T>, ElementError>>::try_convert(self)?;
let hr = unsafe { SafeArrayPutElement(psa, &ix, slf.as_ptr() as *mut c_void)};
match hr {
0 => Ok(()),
_ => Err(ElementError::from(IntoSafeArrElemError::PutElementFailed{hr: hr}))
}
}
}
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for ['DecWrapper']. This allows it to be converted into SAFEARRAY with vt = `VT_DECIMAL`."]DecWrapper => DECIMAL, VT_DECIMAL);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for `i8`. This allows it to be converted into SAFEARRAY with vt = `VT_I1`."]i8, VT_I1);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for `u8`. This allows it to be converted into SAFEARRAY with vt = `VT_UI1`."]u8, VT_UI1);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for `u16`. This allows it to be converted into SAFEARRAY with vt = `VT_UI2`."]u16, VT_UI2);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for `u32`. This allows it to be converted into SAFEARRAY with vt = `VT_UI4`."]u32, VT_UI4);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for [`Int`]. This allows it to be converted into SAFEARRAY with vt = `VT_INT`."]Int => i32, VT_INT);
impl_safe_arr_elem!(#[doc="`SafeArrayElement` impl for [`UInt`]. This allows it to be converted into SAFEARRAY with vt = `VT_INT`."]UInt => u32, VT_UINT);
impl SafeArrayElement for Ptr<IUnknown> {
#[doc(hidden)]
const SFTYPE: u32 = VT_UNKNOWN;
#[doc(hidden)]
type Element = *mut IUnknown;
#[doc(hidden)]
fn from_safearray(psa: *mut SAFEARRAY, ix: i32) -> Result<Self::Element, ElementError> {
let mut def_val: IUnknown = unsafe {mem::zeroed()};
let mut empty = EmptyMemoryDestructor::new(&mut def_val);
#[allow(trivial_casts)]
let hr = unsafe {SafeArrayGetElement(psa, &ix, &mut def_val as *mut _ as *mut c_void)};
match hr {
0 => {
empty.inner = null_mut();
Ok(&mut def_val)
},
_ => {
Err(ElementError::from(FromSafeArrElemError::GetElementFailed{hr: hr}))
}
}
}
#[doc(hidden)]
fn into_safearray(self, psa: *mut SAFEARRAY, ix: i32) -> Result<(), ElementError> {
let slf = self.as_ptr();
let hr = unsafe { SafeArrayPutElement(psa, &ix, slf as *mut c_void)};
match hr {
0 => Ok(()),
_ => Err(ElementError::from(IntoSafeArrElemError::PutElementFailed{hr: hr}))
}
}
}
impl SafeArrayElement for Ptr<IDispatch> {
#[doc(hidden)]
const SFTYPE: u32 = VT_DISPATCH;
#[doc(hidden)]
type Element = *mut IDispatch;
#[doc(hidden)]
fn from_safearray(psa: *mut SAFEARRAY, ix: i32) -> Result<Self::Element, ElementError> {
let mut def_val: IDispatch = unsafe {mem::zeroed()};
let mut empty = EmptyMemoryDestructor::new(&mut def_val);
#[allow(trivial_casts)]
let hr = unsafe {SafeArrayGetElement(psa, &ix, &mut def_val as *mut _ as *mut c_void)};
match hr {
0 => {
empty.inner = null_mut();
Ok(&mut def_val)
},
_ => {
Err(ElementError::from(FromSafeArrElemError::GetElementFailed{hr: hr}))
}
}
}
#[doc(hidden)]
fn into_safearray(self, psa: *mut SAFEARRAY, ix: i32) -> Result<(), ElementError> {
let slf = self.as_ptr();
let hr = unsafe { SafeArrayPutElement(psa, &ix, slf as *mut c_void)};
match hr {
0 => Ok(()),
_ => Err(ElementError::from(IntoSafeArrElemError::PutElementFailed{hr: hr}))
}
}
}
impl TryConvert<Ptr<IUnknown>, ElementError> for *mut IUnknown {
fn try_convert(p: Ptr<IUnknown>) -> Result<Self, ElementError> {
Ok(p.as_ptr())
}
}
impl TryConvert<Ptr<IDispatch>, ElementError> for *mut IDispatch {
fn try_convert(p: Ptr<IDispatch>) -> Result<Self, ElementError> {
Ok(p.as_ptr())
}
}
pub trait SafeArrayExt<T: SafeArrayElement> {
fn into_safearray(&mut self) -> Result<Ptr<SAFEARRAY>, SafeArrayError>;
fn from_safearray(psa: Ptr<SAFEARRAY>) -> Result<Vec<T>, SafeArrayError>;
}
struct SafeArrayDestructor {
inner: *mut SAFEARRAY,
_marker: PhantomData<SAFEARRAY>
}
impl SafeArrayDestructor {
fn new(p: *mut SAFEARRAY) -> SafeArrayDestructor {
assert!(!p.is_null(), "SafeArrayDestructor initialized with null *mut SAFEARRAY pointer.");
SafeArrayDestructor{
inner: p,
_marker: PhantomData
}
}
}
impl Drop for SafeArrayDestructor {
fn drop(&mut self) {
if self.inner.is_null(){
return;
}
unsafe {
SafeArrayDestroy(self.inner)
};
self.inner = null_mut();
}
}
impl<Itr, Elem> SafeArrayExt<Itr::Item> for Itr
where
Itr: ExactSizeIterator,
Itr::Item: SafeArrayElement<Element=Elem> + TryConvert<Elem, ElementError>,
Elem: TryConvert<Itr::Item, ElementError>
{
fn into_safearray(&mut self) -> Result<Ptr<SAFEARRAY>, SafeArrayError > {
let c_elements: ULONG = self.len() as u32;
let vartype = Itr::Item::SFTYPE;
let mut sab = SAFEARRAYBOUND { cElements: c_elements, lLbound: 0i32};
let psa = unsafe { SafeArrayCreate(vartype as u16, 1, &mut sab)};
assert!(!psa.is_null());
let mut sad = SafeArrayDestructor::new(psa);
for (ix, mut elem) in self.enumerate() {
match <Itr::Item as SafeArrayElement>::into_safearray(elem, psa, ix as i32) {
Ok(()) => continue,
Err(e) => return Err(SafeArrayError::from(IntoSafeArrayError::from_element_err(e, ix)))
}
}
sad.inner = null_mut();
Ok(Ptr::with_checked(psa).unwrap())
}
fn from_safearray(psa: Ptr<SAFEARRAY>) -> Result<Vec<Itr::Item>, SafeArrayError> {
let psa = psa.as_ptr();
let _sad = SafeArrayDestructor::new(psa);
let sa_dims = unsafe { SafeArrayGetDim(psa) };
assert!(sa_dims > 0); let vt = unsafe {
let mut vt: VARTYPE = 0;
let hr = SafeArrayGetVartype(psa, &mut vt);
check_and_throw!(hr, {}, {return Err(SafeArrayError::from(FromSafeArrayError::SafeArrayGetVartypeFailed{hr: hr}))});
vt
};
if vt as u32 != Itr::Item::SFTYPE {
return Err(SafeArrayError::from(FromSafeArrayError::VarTypeDoesNotMatch{expected: Itr::Item::SFTYPE, found: vt as u32}));
}
if sa_dims == 1 {
let (l_bound, r_bound) = unsafe {
let mut l_bound: c_long = 0;
let mut r_bound: c_long = 0;
let hr = SafeArrayGetLBound(psa, 1, &mut l_bound);
check_and_throw!(hr, {}, {return Err(SafeArrayError::from(FromSafeArrayError::SafeArrayLBoundFailed{hr: hr}))});
let hr = SafeArrayGetUBound(psa, 1, &mut r_bound);
check_and_throw!(hr, {}, {return Err(SafeArrayError::from(FromSafeArrayError::SafeArrayRBoundFailed{hr: hr}))});
(l_bound, r_bound)
};
let mut vc: Vec<Itr::Item> = Vec::new();
for ix in l_bound..=r_bound {
match Itr::Item::from_safearray(psa, ix) {
Ok(val) => {
let v = match Itr::Item::try_convert(val) {
Ok(v) => v,
Err(ex) => return Err(SafeArrayError::from(FromSafeArrayError::from_element_err(ex, ix as usize))),
};
vc.push(v);
},
Err(e) => return Err(SafeArrayError::from(FromSafeArrayError::from_element_err(e, ix as usize)))
}
}
Ok(vc)
} else {
Err(SafeArrayError::from(FromSafeArrayError::SafeArrayDimsInvalid{sa_dims: sa_dims}))
}
}
}
#[link(name="OleAut32")]
extern "system" {
fn SafeArrayCreate(vt: VARTYPE, cDims: UINT, rgsabound: LPSAFEARRAYBOUND) -> LPSAFEARRAY;
fn SafeArrayDestroy(safe: LPSAFEARRAY)->HRESULT;
fn SafeArrayGetDim(psa: LPSAFEARRAY) -> UINT;
fn SafeArrayGetElement(psa: LPSAFEARRAY, rgIndices: *const c_long, pv: *mut c_void) -> HRESULT;
fn SafeArrayGetLBound(psa: LPSAFEARRAY, nDim: UINT, plLbound: *mut c_long)->HRESULT;
fn SafeArrayGetUBound(psa: LPSAFEARRAY, nDim: UINT, plUbound: *mut c_long)->HRESULT;
fn SafeArrayGetVartype(psa: LPSAFEARRAY, pvt: *mut VARTYPE) -> HRESULT;
fn SafeArrayPutElement(psa: LPSAFEARRAY, rgIndices: *const c_long, pv: *mut c_void) -> HRESULT;
}
#[cfg(test)]
mod test {
use super::*;
use std::vec::IntoIter;
use rust_decimal::Decimal;
macro_rules! validate_safe_arr {
($t:ident, $vals:expr, $vt:expr) => {
let v: Vec<$t> = $vals;
let p = v.into_iter().into_safearray().unwrap();
let r: Result<Vec<$t>, SafeArrayError> = IntoIter::<$t>::from_safearray(p);
let r = r.unwrap();
assert_eq!(r, $vals);
};
}
#[test]
fn test_i16() {
validate_safe_arr!(i16, vec![0,1,2,3,4], VT_I2 );
}
#[test]
fn test_i32() {
validate_safe_arr!(i32, vec![0,1,2,3,4], VT_I4 );
}
#[test]
fn test_f32() {
validate_safe_arr!(f32, vec![0.0f32,-1.333f32,2f32,3f32,4f32], VT_R4 );
}
#[test]
fn test_f64() {
validate_safe_arr!(f64, vec![0.0f64,-1.333f64,2f64,3f64,4f64], VT_R8 );
}
#[test]
fn test_cy() {
validate_safe_arr!(Currency, vec![Currency::from(-1), Currency::from(2)], VT_CY );
}
#[test]
fn test_date() {
validate_safe_arr!(Date, vec![Date::from(0.01), Date::from(100.0/99.0)], VT_DATE );
}
#[test]
fn test_str() {
let v: Vec<U16String> = vec![U16String::from_str("validate"), U16String::from_str("test string")];
let mut v = v.into_iter();
let p = <IntoIter<U16String> as SafeArrayExt<U16String>>::into_safearray(&mut v).unwrap();
let r: Result<Vec<U16String>, SafeArrayError> = IntoIter::from_safearray(p);
let r = r.unwrap();
assert_eq!(r, vec![U16String::from_str("validate"), U16String::from_str("test string")]);
}
#[test]
fn test_scode() {
validate_safe_arr!(SCode, vec![SCode::from(100), SCode::from(10000)], VT_ERROR );
}
#[test]
fn test_bool() {
validate_safe_arr!(VariantBool, vec![VariantBool::from(true), VariantBool::from(false), VariantBool::from(true), VariantBool::from(true), VariantBool::from(false), VariantBool::from(false), VariantBool::from(true)], VT_BOOL );
}
#[test]
fn test_variant() {
let v: Vec<Variant<u64, u64>> = vec![Variant::wrap(100u64)];
let mut p = v.into_iter();
let p = <IntoIter<Variant<u64, u64>> as SafeArrayExt<Variant<u64, u64>>>::into_safearray(&mut p).unwrap();
let r: Result< Vec<Variant<u64, u64>>, SafeArrayError> = IntoIter::from_safearray(p);
let r = r.unwrap();
assert_eq!(r, vec![Variant::wrap(100u64)]);
}
#[test]
fn test_decimal() {
validate_safe_arr!(DecWrapper, vec![DecWrapper::from(Decimal::new(2, 2)), DecWrapper::from(Decimal::new(3, 3))], VE_DECIMAL );
}
#[test]
fn test_i8() {
validate_safe_arr!(i8, vec![-1, 0,1,2,3,4], VT_I1 );
}
#[test]
fn test_u8() {
validate_safe_arr!(u8, vec![0,1,2,3,4], VT_UI1 );
}
#[test]
fn test_u16() {
validate_safe_arr!(u16, vec![0,1,2,3,4], VT_UI2 );
}
#[test]
fn test_u32() {
validate_safe_arr!(u32, vec![0,1,2,3,4], VT_UI4 );
}
}