use std::fmt::Display;
use std::mem::ManuallyDrop;
use std::ptr::null_mut;
use windows::core::BSTR;
use windows::core::HRESULT;
use windows::core::HSTRING;
use windows::core::IUnknown;
use windows::core::Interface;
use windows::core::PSTR;
use windows::Win32::Foundation::DECIMAL;
use windows::Win32::Foundation::VARIANT_BOOL;
use windows::Win32::System::Com::*;
use windows::Win32::System::Ole::*;
use windows::Win32::System::Variant::*;
use super::Error;
use super::Result;
use super::errors::ERR_NULL_PTR;
use super::errors::ERR_TYPE;
#[derive(Clone)]
pub enum Value {
EMPTY,
NULL,
VOID,
I1(i8),
I2(i16),
I4(i32),
I8(i64),
INT(i32),
UI1(u8),
UI2(u16),
UI4(u32),
UI8(u64),
UINT(u32),
R4(f32),
R8(f64),
CURRENCY(i64),
DATE(f64),
STRING(String),
UNKNOWN(IUnknown),
DISPATCH(IDispatch),
ERROR(HRESULT),
HRESULT(HRESULT),
BOOL(bool),
VARIANT(Variant),
DECIMAL(DECIMAL),
SAFEARRAY(SafeArray),
ArrayBool(Vec<bool>),
ArrayR8(Vec<f64>),
ArrayI2(Vec<i16>),
ArrayI4(Vec<i32>),
ArrayI8(Vec<i64>),
ArrayUI2(Vec<u16>),
ArrayUI4(Vec<u32>),
ArrayUI8(Vec<u64>),
ArrayString(Vec<String>)
}
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::EMPTY => write!(f, "EMPTY"),
Value::NULL => write!(f, "NULL"),
Value::VOID => write!(f, "VOID"),
Value::I1(value) => write!(f, "I1({})", value),
Value::I2(value) => write!(f, "I2({})", value),
Value::I4(value) => write!(f, "I4({})", value),
Value::I8(value) => write!(f, "I8({})", value),
Value::INT(value) => write!(f, "INT({})", value),
Value::UI1(value) => write!(f, "UI1({})", value),
Value::UI2(value) => write!(f, "UI2({})", value),
Value::UI4(value) => write!(f, "UI4({})", value),
Value::UI8(value) => write!(f, "UI8({})", value),
Value::UINT(value) => write!(f, "UNIT({})", value),
Value::R4(value) => write!(f, "R4({})", value),
Value::R8(value) => write!(f, "R8({})", value),
Value::CURRENCY(value) => write!(f, "CY({})", value),
Value::DATE(value) => write!(f, "DATE({})", value),
Value::STRING(value) => write!(f, "STRING({})", value),
Value::UNKNOWN(_) => write!(f, "UNKNOWN"),
Value::DISPATCH(_) => write!(f, "DISPATCH"),
Value::ERROR(value) => write!(f, "ERROR({})", value.0),
Value::HRESULT(value) => write!(f, "HRESULT({})", value.0),
Value::BOOL(value) => write!(f, "BOOL({})", value),
Value::VARIANT(value) => write!(f, "VARIANT({})", value),
Value::DECIMAL(_) => write!(f, "DECIMAL"),
Value::SAFEARRAY(value) => write!(f, "SAFEARRAY({})", value),
Value::ArrayBool(value) => fmt_array(f, value),
Value::ArrayR8(value) => fmt_array(f, value),
Value::ArrayI2(value) => fmt_array(f, value),
Value::ArrayI4(value) => fmt_array(f, value),
Value::ArrayI8(value) => fmt_array(f, value),
Value::ArrayUI2(value) => fmt_array(f, value),
Value::ArrayUI4(value) => fmt_array(f, value),
Value::ArrayUI8(value) => fmt_array(f, value),
Value::ArrayString(value) => fmt_array(f, value),
}
}
}
fn fmt_array<D: Display>(f: &mut std::fmt::Formatter<'_>, arr: &Vec<D>) -> std::fmt::Result {
write!(f, "ARRAY(")?;
for (i, v) in arr.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", v)?;
}
write!(f, ")")
}
#[derive(Clone, Default)]
pub struct Variant {
value: VARIANT
}
impl Variant {
fn new_null(vt: VARENUM) -> Variant {
let mut val = VARIANT_0_0::default();
val.vt = vt;
let val = VARIANT {
Anonymous: VARIANT_0 {
Anonymous: ManuallyDrop::new(val)
}
};
val.into()
}
fn new(vt: VARENUM, value: VARIANT_0_0_0) -> Variant {
let val = VARIANT {
Anonymous: VARIANT_0 {
Anonymous: ManuallyDrop::new(VARIANT_0_0 {
vt,
Anonymous: value,
wReserved1: 0,
wReserved2: 0,
wReserved3: 0,
})
}
};
val.into()
}
fn vt(&self) -> VARENUM {
self.value.vt()
}
pub fn get_type(&self) -> VARENUM {
self.vt()
}
pub(crate) fn get_data(&self) -> &VARIANT_0_0_0 {
unsafe { &self.value.Anonymous.Anonymous.Anonymous }
}
fn as_bool(&self) -> VARIANT_BOOL {
unsafe { self.get_data().boolVal }
}
fn as_decimal(&self) -> DECIMAL {
unsafe {
let d = self.get_data().pdecVal;
DECIMAL {
wReserved: (*d).wReserved,
Anonymous1: windows::Win32::Foundation::DECIMAL_0 { signscale: (*d).Anonymous1.signscale },
Hi32: (*d).Hi32,
Anonymous2: windows::Win32::Foundation::DECIMAL_1 { Lo64: (*d).Anonymous2.Lo64 }
}
}
}
fn as_currency(&self) -> CY {
CY {
int64: unsafe { self.get_data().cyVal.int64 }
}
}
pub fn get_value(&self) -> Result<Value> {
self.try_into()
}
pub fn is_null(&self) -> bool {
let vt = self.vt();
vt == VT_EMPTY || vt == VT_NULL || vt == VT_VOID
}
pub fn is_string(&self) -> bool {
let vt = self.vt();
vt == VT_BSTR || vt == VT_LPWSTR || vt == VT_LPSTR
}
pub fn get_string(&self) -> Result<String> {
let value = self.get_value()?;
match value {
Value::STRING(str) => Ok(str),
_ => Err(Error::new(ERR_TYPE, "Error Variant Type"))
}
}
pub fn is_array(&self) -> bool {
let vt = self.vt();
vt == VT_SAFEARRAY || (vt.0 & VT_ARRAY.0) != 0
}
pub fn get_array(&self) -> Result<SafeArray> {
let value = self.get_value()?;
match value {
Value::SAFEARRAY(arr) => Ok(arr),
Value::ArrayBool(arr) => arr.try_into(),
Value::ArrayR8(arr) => arr.try_into(),
Value::ArrayI2(arr) => arr.try_into(),
Value::ArrayI4(arr) => arr.try_into(),
Value::ArrayI8(arr) => arr.try_into(),
Value::ArrayUI2(arr) => arr.try_into(),
Value::ArrayUI4(arr) => arr.try_into(),
Value::ArrayUI8(arr) => arr.try_into(),
Value::ArrayString(arr) => arr.try_into(),
_ => Err(Error::new(ERR_TYPE, "Error Variant Type"))
}
}
pub fn abs(&self) -> Result<Variant> {
let v = unsafe {
VarAbs(&self.value)?
};
Ok(v.into())
}
pub fn add(&self, augend: &Variant) -> Result<Variant> {
let v = unsafe {
VarAdd(&self.value, &augend.value)?
};
Ok(v.into())
}
pub fn subtract(&self, subtrahend: &Variant) -> Result<Variant> {
let v = unsafe {
VarSub(&self.value, &subtrahend.value)?
};
Ok(v.into())
}
pub fn multiply(&self, multiplicand: &Variant) -> Result<Variant> {
let v = unsafe {
VarMul(&self.value, &multiplicand.value)?
};
Ok(v.into())
}
pub fn divide(&self, divisor: &Variant) -> Result<Variant> {
let v = unsafe {
VarDiv(&self.value, &divisor.value)?
};
Ok(v.into())
}
pub fn mod_by(&self, m: &Variant) -> Result<Variant> {
let v = unsafe {
VarMod(&self.value, &m.value)?
};
Ok(v.into())
}
pub fn negate(&self) -> Result<Variant> {
let v = unsafe {
VarNeg(&self.value)?
};
Ok(v.into())
}
pub fn not(&self) -> Result<Variant> {
let v = unsafe {
VarNot(&self.value)?
};
Ok(v.into())
}
pub fn and(&self, val: &Variant) -> Result<Variant> {
let v = unsafe {
VarAnd(&self.value, &val.value)?
};
Ok(v.into())
}
pub fn or(&self, val: &Variant) -> Result<Variant> {
let v = unsafe {
VarOr(&self.value, &val.value)?
};
Ok(v.into())
}
pub fn xor(&self, val: &Variant) -> Result<Variant> {
let v = unsafe {
VarXor(&self.value, &val.value)?
};
Ok(v.into())
}
}
impl From<VARIANT> for Variant {
fn from(value: VARIANT) -> Self {
Self {
value
}
}
}
impl From<&VARIANT> for Variant {
fn from(value: &VARIANT) -> Self {
value.clone().into()
}
}
impl Into<VARIANT> for Variant {
fn into(self) -> VARIANT {
self.value
}
}
impl AsRef<VARIANT> for Variant {
fn as_ref(&self) -> &VARIANT {
&self.value
}
}
impl Display for Variant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Ok(val) = self.get_value() {
write!(f, "{}", val)
} else {
Err(std::fmt::Error {})
}
}
}
macro_rules! val_to_variant {
($v: expr) => {
{
let variant = VARIANT::from($v);
variant.into()
}
};
}
macro_rules! vec_to_variant {
($v: expr, $t: expr) => {
{
let vt = VARENUM(VT_ARRAY.0 | $t.0);
let arr: SafeArray = $v.try_into().unwrap();
Variant::new(vt, VARIANT_0_0_0 { parray: arr.into() })
}
};
}
impl From<Value> for Variant {
fn from(value: Value) -> Self {
match value {
Value::EMPTY => Variant::new_null(VT_EMPTY),
Value::NULL => Variant::new_null(VT_NULL),
Value::VOID => Variant::new_null(VT_VOID),
Value::I1(v) => val_to_variant!(v),
Value::I2(v) => val_to_variant!(v),
Value::I4(v) => val_to_variant!(v),
Value::I8(v) => val_to_variant!(v),
Value::INT(v) => val_to_variant!(v),
Value::UI1(v) => val_to_variant!(v),
Value::UI2(v) => val_to_variant!(v),
Value::UI4(v) => val_to_variant!(v),
Value::UI8(v) => val_to_variant!(v),
Value::UINT(v) => val_to_variant!(v),
Value::R4(v) => val_to_variant!(v),
Value::R8(v) => val_to_variant!(v),
Value::CURRENCY(v) => Variant::new(VT_CY, VARIANT_0_0_0 { cyVal: CY { int64: v} }),
Value::DATE(v) => Variant::new(VT_DATE, VARIANT_0_0_0 { date: v }),
Value::STRING(v) => val_to_variant!(BSTR::from(v)),
Value::UNKNOWN(v) => val_to_variant!(v),
Value::DISPATCH(v) => val_to_variant!(v),
Value::ERROR(v) => Variant::new(VT_ERROR, VARIANT_0_0_0 { intVal: v.0 }),
Value::HRESULT(v) => Variant::new(VT_HRESULT, VARIANT_0_0_0 { intVal: v.0 }),
Value::BOOL(v) => val_to_variant!(v),
Value::VARIANT(v) => {
let mut val = v.value.clone();
Variant::new(VT_VARIANT, VARIANT_0_0_0 { pvarVal: &mut val as _ })
},
Value::DECIMAL(v) => {
let mut decimal = v;
Variant::new(VT_DECIMAL, VARIANT_0_0_0 { pdecVal: &mut decimal as _ })
},
Value::SAFEARRAY(v) => Variant::new(VT_SAFEARRAY, VARIANT_0_0_0 { parray: v.into() }),
Value::ArrayBool(v) => vec_to_variant!(v, VT_BOOL),
Value::ArrayR8(v) => vec_to_variant!(v, VT_R8),
Value::ArrayI2(v) => vec_to_variant!(v, VT_I2),
Value::ArrayI4(v) => vec_to_variant!(v, VT_I4),
Value::ArrayI8(v) => vec_to_variant!(v, VT_I8),
Value::ArrayUI2(v) => vec_to_variant!(v, VT_UI2),
Value::ArrayUI4(v) => vec_to_variant!(v, VT_UI4),
Value::ArrayUI8(v) => vec_to_variant!(v, VT_UI8),
Value::ArrayString(v) => vec_to_variant!(v, VT_BSTR),
}
}
}
macro_rules! variant_as_vec {
($fetch: ident, $variant: expr) => {
{
let count = unsafe { VariantGetElementCount(&$variant) };
let mut arr = Vec::with_capacity(count as _);
for i in 0..count {
let val = unsafe { $fetch(&$variant, i)? };
arr.push(val);
}
arr
}
};
}
impl TryInto<Value> for &Variant {
type Error = Error;
fn try_into(self) -> Result<Value> {
let vt = self.vt();
if vt.0 & VT_ARRAY.0 != 0 {
let t = VARENUM(vt.0 & VT_TYPEMASK.0);
match t {
VT_BOOL => {
let arr = variant_as_vec!(VariantGetBooleanElem, self.value);
Ok(Value::ArrayBool(arr.into_iter().map(|v| v.as_bool()).collect()))
}
VT_R8 => Ok(Value::ArrayR8(variant_as_vec!(VariantGetDoubleElem, self.value))),
VT_I2 => Ok(Value::ArrayI2(variant_as_vec!(VariantGetInt16Elem, self.value))),
VT_I4 => Ok(Value::ArrayI4(variant_as_vec!(VariantGetInt32Elem, self.value))),
VT_I8 => Ok(Value::ArrayI8(variant_as_vec!(VariantGetInt64Elem, self.value))),
VT_UI2 => Ok(Value::ArrayUI2(variant_as_vec!(VariantGetUInt16Elem, self.value))),
VT_UI4 => Ok(Value::ArrayUI4(variant_as_vec!(VariantGetUInt32Elem, self.value))),
VT_UI8 => Ok(Value::ArrayUI8(variant_as_vec!(VariantGetUInt64Elem, self.value))),
VT_BSTR | VT_LPWSTR | VT_LPSTR => {
let arr = variant_as_vec!(VariantGetStringElem, self.value);
Ok(Value::ArrayString(arr.into_iter().map(|v| unsafe { v.to_string().unwrap() }).collect()))
}
_ => Err(Error::new(ERR_TYPE, "unknown variant type"))
}
} else if vt == VT_EMPTY {
Ok(Value::EMPTY)
} else if vt == VT_NULL {
Ok(Value::NULL)
} else if vt == VT_VOID {
Ok(Value::VOID)
} else if vt == VT_I1 {
let val = unsafe {
self.get_data().bVal as i8
};
Ok(Value::I1(val))
} else if vt == VT_I2 {
let val = unsafe {
self.get_data().iVal
};
Ok(Value::I2(val))
} else if vt == VT_I4 {
let val = unsafe {
self.get_data().lVal
};
Ok(Value::I4(val))
} else if vt == VT_I8 {
let val = unsafe {
self.get_data().llVal
};
Ok(Value::I8(val))
} else if vt == VT_INT {
let val = unsafe {
self.get_data().lVal
};
Ok(Value::INT(val))
} else if vt == VT_UI1 {
let val = unsafe {
self.get_data().bVal
};
Ok(Value::UI1(val))
} else if vt == VT_UI2 {
let val = unsafe {
self.get_data().uiVal
};
Ok(Value::UI2(val))
} else if vt == VT_UI4 {
let val = unsafe {
self.get_data().ulVal
};
Ok(Value::UI4(val))
} else if vt == VT_UI8 {
let val = unsafe {
self.get_data().ullVal
};
Ok(Value::UI8(val))
} else if vt == VT_UINT {
let val = unsafe {
self.get_data().uintVal
};
Ok(Value::UINT(val))
} else if vt == VT_R4 {
let val = unsafe {
self.get_data().fltVal
};
Ok(Value::R4(val))
} else if vt == VT_R8 {
let val = unsafe {
self.get_data().dblVal
};
Ok(Value::R8(val))
} else if vt == VT_CY {
let val = unsafe {
self.get_data().cyVal.int64
};
Ok(Value::CURRENCY(val))
} else if vt == VT_DATE {
let val = unsafe {
self.get_data().date
};
Ok(Value::DATE(val))
} else if vt == VT_BSTR || vt == VT_LPSTR {
let val = unsafe { self.get_data().bstrVal.to_string() };
Ok(Value::STRING(val))
} else if vt == VT_LPSTR {
let val = unsafe {
if self.get_data().pcVal.is_null() {
String::from("")
} else {
let lpstr = self.get_data().pcVal;
lpstr.to_string()?
}
};
Ok(Value::STRING(val))
} else if vt == VT_DISPATCH {
let val = if let Ok(disp) = IDispatch::try_from(&self.value) {
Value::DISPATCH(disp)
} else {
Value::NULL
};
Ok(val)
} else if vt == VT_UNKNOWN {
let val = if let Ok(unk) = IUnknown::try_from(&self.value) {
Value::UNKNOWN(unk)
} else {
Value::NULL
};
Ok(val)
} else if vt == VT_ERROR {
let val = unsafe {
self.get_data().intVal
};
Ok(Value::HRESULT(HRESULT(val)))
} else if vt == VT_HRESULT {
let val = unsafe {
self.get_data().intVal
};
Ok(Value::HRESULT(HRESULT(val)))
} else if vt == VT_BOOL {
let val = unsafe {
self.get_data().__OBSOLETE__VARIANT_BOOL.as_bool()
};
Ok(Value::BOOL(val))
} else if vt == VT_VARIANT {
let val = unsafe {
(*self.get_data().pvarVal).clone()
};
Ok(Value::VARIANT(val.into()))
} else if vt == VT_DECIMAL {
let val = self.as_decimal();
Ok(Value::DECIMAL(val))
} else if vt == VT_SAFEARRAY {
let arr = unsafe {
self.get_data().parray.clone()
};
Ok(Value::SAFEARRAY(SafeArray::from(arr)))
} else {
Err(Error::new(ERR_TYPE, "unknown variant type"))
}
}
}
impl TryInto<Value> for Variant {
type Error = Error;
fn try_into(self) -> Result<Value> {
(&self).try_into()
}
}
impl From<bool> for Variant {
fn from(value: bool) -> Self {
Value::BOOL(value).into()
}
}
impl TryInto<bool> for &Variant {
type Error = Error;
fn try_into(self) -> Result<bool> {
let val = unsafe {
match self.get_type() {
VT_BOOL => self.as_bool(),
VT_CY => VarBoolFromCy(self.as_currency())?,
VT_DATE => VarBoolFromDate(self.get_data().date)?,
VT_DECIMAL => VarBoolFromDec(&self.as_decimal())?,
VT_I1 => VarBoolFromI1(self.get_data().cVal)?,
VT_I2 => VarBoolFromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => VarBoolFromI4(self.get_data().lVal)?,
VT_I8 => VarBoolFromI8(self.get_data().llVal)?,
VT_R4 => VarBoolFromR4(self.get_data().fltVal)?,
VT_R8 => VarBoolFromR8(self.get_data().dblVal)?,
VT_BSTR | VT_LPWSTR | VT_LPSTR => {
let str = self.get_string()?;
let str: HSTRING = str.into();
VarBoolFromStr(&str, 0, 0)?
},
VT_UI1 => VarBoolFromUI1(self.get_data().bVal)?,
VT_UI2 => VarBoolFromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => VarBoolFromUI4(self.get_data().ulVal)?,
VT_UI8 => VarBoolFromUI8(self.get_data().ullVal)?,
VT_DISPATCH => if let Ok(ref disp) = IDispatch::try_from(&self.value) { VarBoolFromDisp(disp, 0)?
} else {
false.into()
},
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val.as_bool())
}
}
impl TryInto<bool> for Variant {
type Error = Error;
fn try_into(self) -> Result<bool> {
(&self).try_into()
}
}
impl From<&str> for Variant {
fn from(value: &str) -> Self {
Value::STRING(value.into()).into()
}
}
impl From<String> for Variant {
fn from(value: String) -> Self {
value.as_str().into()
}
}
impl From<&String> for Variant {
fn from(value: &String) -> Self {
value.as_str().into()
}
}
impl TryInto<String> for &Variant {
type Error = Error;
fn try_into(self) -> Result<String> {
if self.is_string() {
self.get_string()
} else {
let str: BSTR = unsafe {
match self.get_type() {
VT_BOOL => VarBstrFromBool(self.as_bool(), 0, 0)?,
VT_CY => VarBstrFromCy(self.as_currency(), 0, 0)?,
VT_DATE => VarBstrFromDate(self.get_data().date, 0, 0)?,
VT_DECIMAL => VarBstrFromDec(&self.as_decimal(), 0, 0)?,
VT_DISPATCH => if let Ok(ref disp) = IDispatch::try_from(&self.value) {
VarBstrFromDisp(disp, 0, 0)?
} else {
BSTR::default()
},
VT_I1 => VarBstrFromI1(self.get_data().cVal, 0, 0)?,
VT_I2 => VarBstrFromI2(self.get_data().iVal, 0, 0)?,
VT_I4 | VT_INT => VarBstrFromI4(self.get_data().lVal, 0, 0)?,
VT_I8 => VarBstrFromI8(self.get_data().llVal, 0, 0)?,
VT_R4 => VarBstrFromR4(self.get_data().fltVal, 0, 0)?,
VT_R8 => VarBstrFromR8(self.get_data().dblVal, 0, 0)?,
VT_UI1 => VarBstrFromUI1(self.get_data().bVal, 0, 0)?,
VT_UI2 => VarBstrFromUI2(self.get_data().uiVal, 0, 0)?,
VT_UI4 | VT_UINT => VarBstrFromUI4(self.get_data().ulVal, 0, 0)?,
VT_UI8 => VarBstrFromUI8(self.get_data().ullVal, 0, 0)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(str.to_string())
}
}
}
impl TryInto<String> for Variant {
type Error = Error;
fn try_into(self) -> Result<String> {
(&self).try_into()
}
}
impl From<i8> for Variant {
fn from(value: i8) -> Self {
Value::I1(value).into()
}
}
macro_rules! variant_as_i1 {
($func:ident, $value:expr) => {
{
let pc = PSTR::null();
$func($value, pc)?;
(*pc.0) as i8
}
};
}
macro_rules! variant_atoi {
($func:ident, $value:expr) => {
{
let str = $value;
let str: HSTRING = str.into();
$func(&str, 0, 0)?
}
};
}
macro_rules! variant_as_type {
($f:ident, $T:ty, $value:expr) => {
{
let mut v: [$T; 1] = [0 as _];
$f($value, v.as_mut_ptr())?;
v[0]
}
};
}
macro_rules! dispatch_as_type {
($self:ident, $f:ident) => {
{
if let Ok(ref disp) = IDispatch::try_from(&$self.value) {
$f(disp, 0)?
} else {
0 as _
}
}
};
}
impl TryInto<i8> for &Variant {
type Error = Error;
fn try_into(self) -> Result<i8> {
let val: i8 = unsafe {
match self.get_type() {
VT_BOOL => variant_as_i1!(VarI1FromBool, self.as_bool()),
VT_CY => variant_as_i1!(VarI1FromCy, self.as_currency()),
VT_DATE => variant_as_i1!(VarI1FromDate, self.get_data().date),
VT_DECIMAL => variant_as_i1!(VarI1FromDec, &self.as_decimal()),
VT_DISPATCH => if let Ok(ref disp) = IDispatch::try_from(&self.value) {
let pc = PSTR::null();
VarI1FromDisp(disp, 0, pc)?;
*pc.0 as i8
} else {
0i8
},
VT_I1 => self.get_data().bVal as i8,
VT_I2 => variant_as_i1!(VarI1FromI2, self.get_data().iVal),
VT_I4 | VT_INT => variant_as_i1!(VarI1FromI4, self.get_data().lVal),
VT_I8 => variant_as_i1!(VarI1FromI8, self.get_data().llVal),
VT_R4 => variant_as_i1!(VarI1FromR4, self.get_data().fltVal),
VT_R8 => variant_as_i1!(VarI1FromR8, self.get_data().dblVal),
VT_BSTR | VT_LPWSTR | VT_LPSTR => {
let str = self.get_string()?;
let str: HSTRING = str.into();
let pc = PSTR::null();
VarI1FromStr(&str, 0, 0, pc)?;
(*pc.0) as i8
},
VT_UI1 => variant_as_i1!(VarI1FromUI1, self.get_data().bVal),
VT_UI2 => variant_as_i1!(VarI1FromUI2, self.get_data().uiVal),
VT_UI4 | VT_UINT => variant_as_i1!(VarI1FromUI4, self.get_data().ulVal),
VT_UI8 => variant_as_i1!(VarI1FromUI8, self.get_data().ullVal),
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<i8> for Variant {
type Error = Error;
fn try_into(self) -> Result<i8> {
(&self).try_into()
}
}
impl From<i16> for Variant {
fn from(value: i16) -> Self {
Value::I2(value).into()
}
}
impl TryInto<i16> for &Variant {
type Error = Error;
fn try_into(self) -> Result<i16> {
let val: i16 = unsafe {
match self.get_type() {
VT_BOOL => VarI2FromBool(self.as_bool())?,
VT_CY => variant_as_type!(VarI2FromCy, i16, self.as_currency()),
VT_DATE => VarI2FromDate(self.get_data().date)?,
VT_DECIMAL => VarI2FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarI2FromDisp),
VT_I1 => VarI2FromI1(self.get_data().cVal)?,
VT_I2 => self.get_data().iVal,
VT_I4 | VT_INT => VarI2FromI4(self.get_data().lVal)?,
VT_I8 => VarI2FromI8(self.get_data().llVal)?,
VT_R4 => VarI2FromR4(self.get_data().fltVal)?,
VT_R8 => VarI2FromR8(self.get_data().dblVal)?,
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarI2FromStr, self.get_string()?),
VT_UI1 => VarI2FromUI1(self.get_data().bVal)?,
VT_UI2 => VarI2FromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => VarI2FromUI4(self.get_data().ulVal)?,
VT_UI8 => VarI2FromUI8(self.get_data().ullVal)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<i16> for Variant {
type Error = Error;
fn try_into(self) -> Result<i16> {
(&self).try_into()
}
}
impl From<i32> for Variant {
fn from(value: i32) -> Self {
Value::I4(value).into()
}
}
impl TryInto<i32> for &Variant {
type Error = Error;
fn try_into(self) -> Result<i32> {
let val: i32 = unsafe {
match self.get_type() {
VT_BOOL => VarI4FromBool(self.as_bool())?,
VT_CY => VarI4FromCy(self.as_currency())?,
VT_DATE => VarI4FromDate(self.get_data().date)?,
VT_DECIMAL => VarI4FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarI4FromDisp),
VT_I1 => VarI4FromI1(self.get_data().cVal)?,
VT_I2 => VarI4FromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => self.get_data().lVal,
VT_I8 => VarI4FromI8(self.get_data().llVal)?,
VT_R4 => VarI4FromR4(self.get_data().fltVal)?,
VT_R8 => VarI4FromR8(self.get_data().dblVal)?,
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarI4FromStr, self.get_string()?),
VT_UI1 => VarI4FromUI1(self.get_data().bVal)?,
VT_UI2 => VarI4FromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => VarI4FromUI4(self.get_data().ulVal)?,
VT_UI8 => VarI4FromUI8(self.get_data().ullVal)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<i32> for Variant {
type Error = Error;
fn try_into(self) -> Result<i32> {
(&self).try_into()
}
}
impl From<i64> for Variant {
fn from(value: i64) -> Self {
Value::I8(value).into()
}
}
impl TryInto<i64> for &Variant {
type Error = Error;
fn try_into(self) -> Result<i64> {
let val: i64 = unsafe {
match self.get_type() {
VT_BOOL => VarI8FromBool(self.as_bool())?,
VT_CY => VarI8FromCy(self.as_currency())?,
VT_DATE => VarI8FromDate(self.get_data().date)?,
VT_DECIMAL => VarI8FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarI8FromDisp),
VT_I1 => VarI8FromI1(self.get_data().cVal)?,
VT_I2 => VarI8FromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => self.get_data().lVal as i64,
VT_I8 => self.get_data().llVal,
VT_R4 => VarI8FromR4(self.get_data().fltVal)?,
VT_R8 => VarI8FromR8(self.get_data().dblVal)?,
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarI8FromStr, self.get_string()?),
VT_UI1 => VarI8FromUI1(self.get_data().bVal)?,
VT_UI2 => VarI8FromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => VarI8FromUI4(self.get_data().ulVal)?,
VT_UI8 => VarI8FromUI8(self.get_data().ullVal)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<i64> for Variant {
type Error = Error;
fn try_into(self) -> Result<i64> {
(&self).try_into()
}
}
impl From<f32> for Variant {
fn from(value: f32) -> Self {
Value::R4(value).into()
}
}
impl TryInto<f32> for &Variant {
type Error = Error;
fn try_into(self) -> Result<f32> {
let val: f32 = unsafe {
match self.get_type() {
VT_BOOL => VarR4FromBool(self.as_bool())?,
VT_CY => variant_as_type!(VarR4FromCy, f32, self.as_currency()),
VT_DATE => VarR4FromDate(self.get_data().date)?,
VT_DECIMAL => VarR4FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarR4FromDisp),
VT_I1 => VarR4FromI1(self.get_data().cVal)?,
VT_I2 => VarR4FromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => VarR4FromI4(self.get_data().lVal)?,
VT_I8 => VarR4FromI8(self.get_data().llVal)?,
VT_R4 => self.get_data().fltVal,
VT_R8 => VarR4FromR8(self.get_data().dblVal)?,
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarR4FromStr, self.get_string()?),
VT_UI1 => VarR4FromUI1(self.get_data().bVal)?,
VT_UI2 => VarR4FromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => VarR4FromUI4(self.get_data().ulVal)?,
VT_UI8 => VarR4FromUI8(self.get_data().ullVal)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<f32> for Variant {
type Error = Error;
fn try_into(self) -> Result<f32> {
(&self).try_into()
}
}
impl From<f64> for Variant {
fn from(value: f64) -> Self {
Value::R8(value).into()
}
}
impl TryInto<f64> for &Variant {
type Error = Error;
fn try_into(self) -> Result<f64> {
let val: f64 = unsafe {
match self.get_type() {
VT_BOOL => VarR8FromBool(self.as_bool())?,
VT_CY => variant_as_type!(VarR8FromCy, f64, self.as_currency()),
VT_DATE => VarR8FromDate(self.get_data().date)?,
VT_DECIMAL => VarR8FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarR8FromDisp),
VT_I1 => variant_as_type!(VarR8FromI1, f64, self.get_data().cVal),
VT_I2 => VarR8FromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => VarR8FromI4(self.get_data().lVal)?,
VT_I8 => VarR8FromI8(self.get_data().llVal)?,
VT_R4 => VarR8FromR4(self.get_data().fltVal)?,
VT_R8 => self.get_data().dblVal,
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarR8FromStr, self.get_string()?),
VT_UI1 => VarR8FromUI1(self.get_data().bVal)?,
VT_UI2 => VarR8FromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => VarR8FromUI4(self.get_data().ulVal)?,
VT_UI8 => VarR8FromUI8(self.get_data().ullVal)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<f64> for Variant {
type Error = Error;
fn try_into(self) -> Result<f64> {
(&self).try_into()
}
}
impl From<u8> for Variant {
fn from(value: u8) -> Self {
Value::UI1(value).into()
}
}
impl TryInto<u8> for &Variant {
type Error = Error;
fn try_into(self) -> Result<u8> {
let val: u8 = unsafe {
match self.get_type() {
VT_BOOL => VarUI1FromBool(self.as_bool())?,
VT_CY => VarUI1FromCy(self.as_currency())?,
VT_DATE => VarUI1FromDate(self.get_data().date)?,
VT_DECIMAL => VarUI1FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarUI1FromDisp),
VT_I1 => VarUI1FromI1(self.get_data().cVal)?,
VT_I2 => VarUI1FromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => VarUI1FromI4(self.get_data().lVal)?,
VT_I8 => VarUI1FromI8(self.get_data().llVal)?,
VT_R4 => VarUI1FromR4(self.get_data().fltVal)?,
VT_R8 => VarUI1FromR8(self.get_data().dblVal)?,
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarUI1FromStr, self.get_string()?),
VT_UI1 => self.get_data().bVal,
VT_UI2 => VarUI1FromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => VarUI1FromUI4(self.get_data().ulVal)?,
VT_UI8 => VarUI1FromUI8(self.get_data().ullVal)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<u8> for Variant {
type Error = Error;
fn try_into(self) -> Result<u8> {
(&self).try_into()
}
}
impl From<u16> for Variant {
fn from(value: u16) -> Self {
Value::UI2(value).into()
}
}
impl TryInto<u16> for &Variant {
type Error = Error;
fn try_into(self) -> Result<u16> {
let val: u16 = unsafe {
match self.get_type() {
VT_BOOL => VarUI2FromBool(self.as_bool())?,
VT_CY => VarUI2FromCy(self.as_currency())?,
VT_DATE => VarUI2FromDate(self.get_data().date)?,
VT_DECIMAL => VarUI2FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarUI2FromDisp),
VT_I1 => VarUI2FromI1(self.get_data().cVal)?,
VT_I2 => VarUI2FromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => VarUI2FromI4(self.get_data().lVal)?,
VT_I8 => VarUI2FromI8(self.get_data().llVal)?,
VT_R4 => VarUI2FromR4(self.get_data().fltVal)?,
VT_R8 => variant_as_type!(VarUI2FromR8, u16, self.get_data().dblVal),
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarUI2FromStr, self.get_string()?),
VT_UI1 => VarUI2FromUI1(self.get_data().bVal)?,
VT_UI2 => self.get_data().uiVal,
VT_UI4 | VT_UINT => VarUI2FromUI4(self.get_data().ulVal)?,
VT_UI8 => VarUI2FromUI8(self.get_data().ullVal)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<u16> for Variant {
type Error = Error;
fn try_into(self) -> Result<u16> {
(&self).try_into()
}
}
impl From<u32> for Variant {
fn from(value: u32) -> Self {
Value::UI4(value).into()
}
}
impl TryInto<u32> for &Variant {
type Error = Error;
fn try_into(self) -> Result<u32> {
let val: u32 = unsafe {
match self.get_type() {
VT_BOOL => VarUI4FromBool(self.as_bool())?,
VT_CY => VarUI4FromCy(self.as_currency())?,
VT_DATE => VarUI4FromDate(self.get_data().date)?,
VT_DECIMAL => VarUI4FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarUI4FromDisp),
VT_I1 => VarUI4FromI1(self.get_data().cVal)?,
VT_I2 => VarUI4FromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => VarUI4FromI4(self.get_data().lVal)?,
VT_I8 => VarUI4FromI8(self.get_data().llVal)?,
VT_R4 => VarUI4FromR4(self.get_data().fltVal)?,
VT_R8 => VarUI4FromR8(self.get_data().dblVal)?,
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarUI4FromStr, self.get_string()?),
VT_UI1 => VarUI4FromUI1(self.get_data().bVal)?,
VT_UI2 => VarUI4FromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => self.get_data().ulVal,
VT_UI8 => VarUI4FromUI8(self.get_data().ullVal)?,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<u32> for Variant {
type Error = Error;
fn try_into(self) -> Result<u32> {
(&self).try_into()
}
}
impl From<u64> for Variant {
fn from(value: u64) -> Self {
Value::UI8(value).into()
}
}
impl TryInto<u64> for &Variant {
type Error = Error;
fn try_into(self) -> Result<u64> {
let val: u64 = unsafe {
match self.get_type() {
VT_BOOL => VarUI8FromBool(self.as_bool())?,
VT_CY => VarUI8FromCy(self.as_currency())?,
VT_DATE => VarUI8FromDate(self.get_data().date)?,
VT_DECIMAL => VarUI8FromDec(&self.as_decimal())?,
VT_DISPATCH => dispatch_as_type!(self, VarUI8FromDisp),
VT_I1 => VarUI8FromI1(self.get_data().cVal)?,
VT_I2 => VarUI8FromI2(self.get_data().iVal)?,
VT_I4 | VT_INT => self.get_data().lVal as _,
VT_I8 => VarUI8FromI8(self.get_data().llVal)?,
VT_R4 => VarUI8FromR4(self.get_data().fltVal)?,
VT_R8 => VarUI8FromR8(self.get_data().dblVal)?,
VT_BSTR | VT_LPWSTR | VT_LPSTR => variant_atoi!(VarUI8FromStr, self.get_string()?),
VT_UI1 => VarUI8FromUI1(self.get_data().bVal)?,
VT_UI2 => VarUI8FromUI2(self.get_data().uiVal)?,
VT_UI4 | VT_UINT => VarUI8FromUI4(self.get_data().ulVal)?,
VT_UI8 => self.get_data().ullVal,
_ => return Err(Error::new(ERR_TYPE, "Error Variant Type")),
}
};
Ok(val)
}
}
impl TryInto<u64> for Variant {
type Error = Error;
fn try_into(self) -> Result<u64> {
(&self).try_into()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct SafeArray {
array: *mut SAFEARRAY,
owned: bool
}
impl SafeArray {
pub(crate) fn new(array: *mut SAFEARRAY, owned: bool) -> Self {
Self {
array,
owned
}
}
pub fn is_null(&self) -> bool {
self.array.is_null()
}
pub fn new_vector(var_type: VARENUM, len: u32) -> Result<Self> {
unsafe {
let array = SafeArrayCreateVector(var_type, 0, len);
if array.is_null() {
Err(Error::new(ERR_NULL_PTR, "Create SafeArray Failed"))
} else {
Ok(Self {
array,
owned: true
})
}
}
}
pub fn get_array(&self) -> *mut SAFEARRAY {
self.array
}
pub fn get_var_type(&self) -> Result<VARENUM> {
let vt = unsafe {
SafeArrayGetVartype(self.array)?
};
Ok(vt)
}
pub fn get_dim(&self) -> u32 {
unsafe {
SafeArrayGetDim(self.array)
}
}
pub fn get_lower_bound(&self, dimension: u32) -> Result<i32> {
Ok(unsafe {
SafeArrayGetLBound(self.array, dimension)?
})
}
pub fn get_upper_bound(&self, dimension: u32) -> Result<i32> {
Ok(unsafe {
SafeArrayGetUBound(self.array, dimension)?
})
}
pub fn get_element<T: Default>(&self, index: i32) -> Result<T> {
let indices: [i32; 1] = [index];
let mut value = T::default();
let v_ref: *mut T = &mut value;
unsafe {
SafeArrayGetElement(self.array, indices.as_ptr(), v_ref as _)?
};
Ok(value)
}
pub fn get_interface<T: Interface>(&self, index: i32) -> Result<T> {
let indices: [i32; 1] = [index];
let mut result: Option<T> = None;
let v_ref: *mut Option<T> = &mut result;
unsafe {
SafeArrayGetElement(self.array, indices.as_ptr(),v_ref as _)?
};
if let Some(value) = result {
Ok(value)
} else {
Err(Error::new(ERR_NULL_PTR, "NULL Interface"))
}
}
pub fn put_element<T>(&mut self, index: i32, value: T) -> Result<()> {
let indices: [i32; 1] = [index];
let v_ref: *const T = &value;
unsafe {
SafeArrayPutElement(self.array, indices.as_ptr(), v_ref as _)?
};
Ok(())
}
pub fn into_vector<T: Default>(&self, var_type: VARENUM) -> Result<Vec<T>> {
if self.get_var_type()? != var_type {
return Err(Error::new(ERR_TYPE, "Err SafeArray Type"));
};
if self.get_dim() != 1 {
return Err(Error::new(ERR_TYPE, "Err SafeArray Dimension Count"));
};
let lower = self.get_lower_bound(1)?;
let upper = self.get_upper_bound(1)?;
let mut arr = Vec::with_capacity((upper - lower + 1) as _);
for i in lower..=upper {
let v = self.get_element(i)?;
arr.push(v);
};
Ok(arr)
}
pub fn into_string_vector(&self) -> Result<Vec<String>> {
let bstrs: Vec<BSTR> = self.into_vector(VT_BSTR)?;
let strings: Vec<String> = bstrs.iter().map(|s| s.to_string()).collect();
Ok(strings)
}
pub fn into_interface_vector<T: Interface>(&self) -> Result<Vec<T>> {
let vt = self.get_var_type()?;
if vt != VT_UNKNOWN && vt != VT_DISPATCH {
return Err(Error::new(ERR_TYPE, "Err SafeArray Type"));
}
if self.get_dim() != 1 {
return Err(Error::new(ERR_TYPE, "Err SafeArray Dimension Count"));
};
let lower = self.get_lower_bound(1)?;
let upper = self.get_upper_bound(1)?;
let mut arr = Vec::with_capacity((upper - lower + 1) as _);
for i in lower..=upper {
let v: T = self.get_interface(i)?;
arr.push(v);
};
Ok(arr)
}
pub fn from_vector<T: Default>(var_type: VARENUM, src: &Vec<T>) -> Result<SafeArray> {
Self::from_slice(var_type, &src)
}
pub fn from_slice<T: Default>(var_type: VARENUM, src: &[T]) -> Result<SafeArray> {
let arr = Self::new_vector(var_type, src.len() as _)?;
for i in 0..src.len() {
let indices: [i32; 1] = [i as _];
let v_ref: *const T = &src[i];
unsafe {
SafeArrayPutElement(arr.array, indices.as_ptr(), v_ref as _)?
};
};
Ok(arr)
}
pub fn from_string_vector<T: AsRef<str>>(src: &Vec<T>) -> Result<SafeArray> {
let bstrs: Vec<BSTR> = src.iter().map(|s| s.as_ref().into()).collect();
Self::from_vector(VT_BSTR, &bstrs)
}
}
impl Default for SafeArray {
fn default() -> Self {
Self {
array: null_mut(),
owned: false
}
}
}
impl From<*mut SAFEARRAY> for SafeArray {
fn from(array: *mut SAFEARRAY) -> Self {
Self {
array,
owned: true
}
}
}
impl From<*const SAFEARRAY> for SafeArray {
fn from(value: *const SAFEARRAY) -> Self {
let array: *mut SAFEARRAY = unsafe {
std::mem::transmute(value)
};
Self {
array,
owned: false
}
}
}
impl Into<*mut SAFEARRAY> for SafeArray {
fn into(mut self) -> *mut SAFEARRAY {
self.owned = false;
self.array
}
}
macro_rules! fmt_safe_array {
($vec_type:ty, $self:ident, $f:ident) => {
{
let vals: Result<$vec_type> = $self.try_into();
if vals.is_err() {
return Err(std::fmt::Error {});
}
let vals = vals.unwrap();
write!($f, "[")?;
for (i, v) in vals.iter().enumerate() {
if i > 0 {
write!($f, ", ")?;
}
write!($f, "{}", v)?;
}
write!($f, "]")
}
};
}
impl Display for SafeArray {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let vt = self.get_var_type();
if vt.is_err() {
return Err(std::fmt::Error {});
}
match vt.unwrap() {
VT_BOOL => fmt_safe_array!(Vec<bool>, self, f),
VT_I1 => fmt_safe_array!(Vec<i8>, self, f),
VT_I2 => fmt_safe_array!(Vec<i16>, self, f),
VT_I4 | VT_INT => fmt_safe_array!(Vec<i32>, self, f),
VT_I8 => fmt_safe_array!(Vec<i64>, self, f),
VT_UI1 => fmt_safe_array!(Vec<u8>, self, f),
VT_UI2 => fmt_safe_array!(Vec<u16>, self, f),
VT_UI4 | VT_UINT => fmt_safe_array!(Vec<u32>, self, f),
VT_UI8 => fmt_safe_array!(Vec<u64>, self, f),
VT_R4 => fmt_safe_array!(Vec<f32>, self, f),
VT_R8 => fmt_safe_array!(Vec<f64>, self, f),
VT_BSTR | VT_LPWSTR => fmt_safe_array!(Vec<String>, self, f),
_ => Err(core::fmt::Error {})
}
}
}
impl Clone for SafeArray {
fn clone(&self) -> Self {
let array = if self.owned && !self.array.is_null() {
unsafe {
SafeArrayCopy(self.array).unwrap()
}
} else {
self.array
};
Self {
array,
owned: self.owned
}
}
}
impl Drop for SafeArray {
fn drop(&mut self) {
if self.owned && !self.array.is_null() {
unsafe {
SafeArrayDestroy(self.array).unwrap();
}
self.array = null_mut();
}
}
}
macro_rules! define_array_convertor {
($val_type: ty, $var_type: ident) => {
impl TryFrom<&Vec<$val_type>> for SafeArray {
type Error = Error;
fn try_from(value: &Vec<$val_type>) -> Result<Self> {
Self::from_vector($var_type, value)
}
}
impl TryFrom<Vec<$val_type>> for SafeArray {
type Error = Error;
fn try_from(value: Vec<$val_type>) -> Result<Self> {
Self::from_vector($var_type, &value)
}
}
impl TryFrom<&[$val_type]> for SafeArray {
type Error = Error;
fn try_from(value: &[$val_type]) -> Result<Self> {
Self::from_slice($var_type, value)
}
}
impl TryInto<Vec<$val_type>> for SafeArray {
type Error = Error;
fn try_into(self) -> Result<Vec<$val_type>> {
self.into_vector($var_type)
}
}
impl TryInto<Vec<$val_type>> for &SafeArray {
type Error = Error;
fn try_into(self) -> Result<Vec<$val_type>> {
self.into_vector($var_type)
}
}
};
}
define_array_convertor!(i8, VT_I1);
define_array_convertor!(i16, VT_I2);
define_array_convertor!(i32, VT_I4);
define_array_convertor!(i64, VT_I8);
define_array_convertor!(u8, VT_UI1);
define_array_convertor!(u16, VT_UI2);
define_array_convertor!(u32, VT_UI4);
define_array_convertor!(u64, VT_UI8);
define_array_convertor!(f32, VT_R4);
define_array_convertor!(f64, VT_R8);
impl TryFrom<&Vec<&str>> for SafeArray {
type Error = Error;
fn try_from(value: &Vec<&str>) -> Result<Self> {
Self::from_string_vector(value)
}
}
impl TryFrom<Vec<&str>> for SafeArray {
type Error = Error;
fn try_from(value: Vec<&str>) -> Result<Self> {
Self::from_string_vector(&value)
}
}
impl TryFrom<&Vec<&String>> for SafeArray {
type Error = Error;
fn try_from(value: &Vec<&String>) -> Result<Self> {
Self::from_string_vector(value)
}
}
impl TryFrom<Vec<&String>> for SafeArray {
type Error = Error;
fn try_from(value: Vec<&String>) -> Result<Self> {
Self::from_string_vector(&value)
}
}
impl TryFrom<&Vec<String>> for SafeArray {
type Error = Error;
fn try_from(value: &Vec<String>) -> Result<Self> {
Self::from_string_vector(value)
}
}
impl TryFrom<Vec<String>> for SafeArray {
type Error = Error;
fn try_from(value: Vec<String>) -> Result<Self> {
Self::from_string_vector(&value)
}
}
impl TryInto<Vec<String>> for &SafeArray {
type Error = Error;
fn try_into(self) -> Result<Vec<String>> {
self.into_string_vector()
}
}
impl TryInto<Vec<String>> for SafeArray {
type Error = Error;
fn try_into(self) -> Result<Vec<String>> {
self.into_string_vector()
}
}
impl TryFrom<&Vec<bool>> for SafeArray {
type Error = Error;
fn try_from(value: &Vec<bool>) -> Result<Self> {
let bools: Vec<i16> = value.iter().map(|b| if *b { 1 } else { 0 }).collect();
Self::from_vector(VT_BOOL, &bools)
}
}
impl TryFrom<Vec<bool>> for SafeArray {
type Error = Error;
fn try_from(value: Vec<bool>) -> Result<Self> {
(&value).try_into()
}
}
impl TryInto<Vec<bool>> for &SafeArray {
type Error = Error;
fn try_into(self) -> Result<Vec<bool>> {
let bools: Vec<i16> = self.into_vector(VT_BOOL)?;
Ok(bools.iter().map(|v| *v != 0).collect())
}
}
impl TryInto<Vec<bool>> for SafeArray {
type Error = Error;
fn try_into(self) -> Result<Vec<bool>> {
(&self).try_into()
}
}
#[cfg(test)]
mod tests {
use windows::Win32::System::Variant::VT_BOOL;
use crate::variants::SafeArray;
use crate::variants::Value;
use crate::variants::Variant;
#[test]
fn test_variant_null() {
let v = Variant::from(Value::NULL);
assert!(v.is_null());
}
#[test]
fn test_variant_bool() {
let v: Variant = true.into();
assert!(v.get_type() == VT_BOOL);
let b: bool = v.try_into().unwrap();
assert!(b);
let val = Variant::from(Value::STRING("true".into()));
let b_val: bool = val.try_into().unwrap();
assert!(b_val);
}
#[test]
fn test_variant_string() {
let s = Variant::from(Value::STRING("Hello".into()));
assert!(s.is_string());
assert!(s.get_string().unwrap() == "Hello");
}
#[test]
fn test_safearray_i1() {
let vals: Vec<i8> = vec![1, 2, 3];
let arr: SafeArray = vals.try_into().unwrap();
assert_eq!(arr.get_dim(), 1);
assert_eq!(arr.get_lower_bound(1).unwrap(), 0);
assert_eq!(arr.get_upper_bound(1).unwrap(), 2);
let vals: Vec<i8> = arr.try_into().unwrap();
assert_eq!(vals.len(), 3);
assert_eq!(vals[0], 1);
assert_eq!(vals[1], 2);
assert_eq!(vals[2], 3);
}
#[test]
fn test_safearray_bool() {
let vals = vec![true, false];
let arr: SafeArray = vals.try_into().unwrap();
assert_eq!(arr.get_var_type().unwrap(), VT_BOOL);
assert_eq!(arr.to_string(), "[true, false]");
let vals: Vec<bool> = arr.try_into().unwrap();
assert_eq!(vals.len(), 2);
assert!(vals[0]);
assert!(!vals[1]);
}
}