win-variant 0.3.0

This is a rust crate that aims to provide a more ergonomic way of working with variants in winapi based projects.
Documentation
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};
/// VariantArg is a type to simplify the conversion of rust types into variants
/// that are used by windows APIs. Make sure to use the free_variant(s) functions
/// if you convert the VariantArg to VARIANT.
#[derive(Debug)]
pub enum VariantArg {
    Bool(i16),
    Bstr(Vec<u16>),
    LongLong(i64),
    Long(i32),
    Short(i16),
    Float(f32),
    Double(f64),
    // Date(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);
    }
}