use std::convert::TryFrom;
use widestring::U16CString;
use winapi::{
shared::{
minwindef::UINT,
wtypes::{
VT_BOOL, VT_BSTR, VT_I2, VT_I4, VT_I8, VT_INT, VT_R4, VT_R8, VT_UI2, VT_UI4, VT_UI8,
VT_UINT,
},
},
um::{
oaidl::VARIANT,
oleauto::{SysAllocStringLen, VariantInit},
},
};
use log::trace;
use crate::{SafeArray, VariantArgError, BOOL_FALSE, BOOL_TRUE};
#[derive(Debug)]
pub enum VariantArg {
Bool(i16),
Bstr(Vec<u16>),
LongLong(i64),
Long(i32),
Short(i16),
Float(f32),
Double(f64),
UShort(u16),
ULong(u32),
ULongLong(u64),
Int(i32),
UInt(u32),
SafeArray(SafeArray),
}
impl TryFrom<&str> for VariantArg {
type Error = VariantArgError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let bstr = U16CString::from_str(value)?;
Ok(VariantArg::Bstr(bstr.into_vec()))
}
}
impl TryFrom<&String> for VariantArg {
type Error = VariantArgError;
fn try_from(value: &String) -> Result<Self, Self::Error> {
VariantArg::try_from(value.as_str())
}
}
impl From<i32> for VariantArg {
fn from(val: i32) -> Self {
VariantArg::Int(val)
}
}
impl From<u32> for VariantArg {
fn from(val: u32) -> Self {
VariantArg::UInt(val)
}
}
impl From<f32> for VariantArg {
fn from(val: f32) -> Self {
VariantArg::Float(val)
}
}
impl From<f64> for VariantArg {
fn from(val: f64) -> Self {
VariantArg::Double(val)
}
}
impl From<i16> for VariantArg {
fn from(val: i16) -> Self {
VariantArg::Short(val)
}
}
impl From<u16> for VariantArg {
fn from(val: u16) -> Self {
VariantArg::UShort(val)
}
}
impl From<i64> for VariantArg {
fn from(val: i64) -> Self {
VariantArg::LongLong(val)
}
}
impl From<u64> for VariantArg {
fn from(val: u64) -> Self {
VariantArg::ULongLong(val)
}
}
impl From<bool> for VariantArg {
fn from(val: bool) -> Self {
if val {
VariantArg::Bool(BOOL_TRUE)
} else {
VariantArg::Bool(BOOL_FALSE)
}
}
}
impl From<VariantArg> for VARIANT {
fn from(varg: VariantArg) -> VARIANT {
if let VariantArg::SafeArray(sa) = varg {
return sa.into();
}
let mut v = VARIANT::default();
unsafe {
VariantInit(&mut v);
let n2 = v.n1.n2_mut();
match &varg {
VariantArg::Bool(val) => {
n2.vt = VT_BOOL as u16;
let _val = n2.n3.boolVal_mut();
*_val = *val;
}
VariantArg::Bstr(bstr) => {
let bstr_ptr = SysAllocStringLen(bstr.as_ptr(), bstr.len() as UINT);
n2.vt = VT_BSTR as u16;
let _val = n2.n3.bstrVal_mut();
*_val = bstr_ptr;
trace!("assigning BSTR: {:?}", _val);
}
VariantArg::Double(value) => {
n2.vt = VT_R8 as u16;
let _val = n2.n3.dblVal_mut();
*_val = *value;
}
VariantArg::Float(value) => {
n2.vt = VT_R4 as u16;
let _val = n2.n3.fltVal_mut();
*_val = *value;
}
VariantArg::Long(value) => {
n2.vt = VT_I4 as u16;
let _val = n2.n3.lVal_mut();
*_val = *value;
}
VariantArg::LongLong(value) => {
n2.vt = VT_I8 as u16;
let _val = n2.n3.llVal_mut();
*_val = *value;
}
VariantArg::Short(value) => {
n2.vt = VT_I2 as u16;
let _val = n2.n3.iVal_mut();
*_val = *value;
}
VariantArg::ULong(value) => {
n2.vt = VT_UI4 as u16;
let _val = n2.n3.ulVal_mut();
*_val = *value;
}
VariantArg::ULongLong(value) => {
n2.vt = VT_UI8 as u16;
let _val = n2.n3.ullVal_mut();
*_val = *value
}
VariantArg::UShort(value) => {
n2.vt = VT_UI2 as u16;
let _val = n2.n3.uiVal_mut();
*_val = *value;
}
VariantArg::Int(value) => {
n2.vt = VT_INT as u16;
let _val = n2.n3.intVal_mut();
*_val = *value;
}
VariantArg::UInt(value) => {
n2.vt = VT_UINT as u16;
let _val = n2.n3.uintVal_mut();
*_val = *value;
}
_ => unreachable!(),
}
trace!("VARIANT TYPE: {:}", n2.vt)
}
v
}
}
#[test]
fn it_converts_str_to_bstr_arg() {
let src = "Test Value";
let _arg = VariantArg::try_from(src).unwrap();
if let VariantArg::Bstr(_arg) = _arg {
let bstr = U16CString::from_str(src).unwrap().into_vec();
if !bstr.eq(&_arg) {
panic!("value in argument does not generate a valid wide char array");
}
} else {
panic!("expected argument to be BSTR, got: {:?}", _arg);
}
}
#[test]
fn it_converts_string_to_bstr_arg() {
let src = String::from("Test Value");
let _arg = VariantArg::try_from(&src).unwrap();
if let VariantArg::Bstr(_arg) = _arg {
let bstr = U16CString::from_str(src.as_str()).unwrap().into_vec();
if !bstr.eq(&_arg) {
panic!("value in argument does not generate a valid wide char array");
}
} else {
panic!("expected argument to be BSTR, got: {:?}", _arg);
}
}
#[test]
fn it_converts_i32_to_int_arg() {
let src: i32 = 1234;
let _arg = VariantArg::from(src);
if let VariantArg::Int(_arg) = _arg {
if _arg != src {
panic!("expected {:}, got {:}", src, _arg);
}
} else {
panic!("expected argument to be Int, got {:?}", _arg);
}
}
#[test]
fn it_converts_u32_to_int_arg() {
let src: u32 = 1234;
let _arg = VariantArg::from(src);
if let VariantArg::UInt(_arg) = _arg {
if _arg != src {
panic!("expected {:}, got {:}", src, _arg);
}
} else {
panic!("expected argument to be Uint, got {:?}", _arg);
}
}
#[test]
fn it_converts_f32_to_float_arg() {
let src: f32 = 1234.1;
let _arg = VariantArg::from(src);
if let VariantArg::Float(_arg) = _arg {
if _arg != src {
panic!("expected {:}, got {:}", src, _arg);
}
} else {
panic!("expected argument to be Float, got {:?}", _arg);
}
}
#[test]
fn it_converts_f64_to_double_arg() {
let src: f64 = 1234.1;
let _arg = VariantArg::from(src);
if let VariantArg::Double(_arg) = _arg {
if _arg != src {
panic!("expected {:}, got {:}", src, _arg);
}
} else {
panic!("expected argument to be Double, got {:?}", _arg);
}
}
#[test]
fn it_converts_i16_to_short_arg() {
let src: i16 = 1234;
let _arg = VariantArg::from(src);
if let VariantArg::Short(_arg) = _arg {
if _arg != src {
panic!("expected {:}, got {:}", src, _arg);
}
} else {
panic!("expected argument to be Short, got {:?}", _arg);
}
}
#[test]
fn it_converts_u16_to_ushort_arg() {
let src: u16 = 1234;
let _arg = VariantArg::from(src);
if let VariantArg::UShort(_arg) = _arg {
if _arg != src {
panic!("expected {:}, got {:}", src, _arg);
}
} else {
panic!("expected argument to be Ushort, got {:?}", _arg);
}
}
#[test]
fn it_converts_i64_to_longlong_arg() {
let src: i64 = 1234;
let _arg = VariantArg::from(src);
if let VariantArg::LongLong(_arg) = _arg {
if _arg != src {
panic!("expected {:}, got {:}", src, _arg);
}
} else {
panic!("expected argument to be LongLong, got {:?}", _arg);
}
}
#[test]
fn it_converts_u64_to_ulonglong_arg() {
let src: u64 = 1234;
let _arg = VariantArg::from(src);
if let VariantArg::ULongLong(_arg) = _arg {
if _arg != src {
panic!("expected {:}, got {:}", src, _arg);
}
} else {
panic!("expected argument to be ULongLong, got {:?}", _arg);
}
}
#[test]
fn it_converts_bool_to_bool_arg() {
let src = true;
let _arg = VariantArg::from(src);
if let VariantArg::Bool(_arg) = _arg {
if _arg != BOOL_TRUE {
panic!("expected {:}, got {:}", BOOL_TRUE, _arg);
}
} else {
panic!("expected argument to be Bool, got {:?}", _arg);
}
}