win-variant 0.1.2

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_BSTR, VT_INT, VT_UINT},
    },
    um::{
        oaidl::VARIANT,
        oleauto::{SysAllocStringLen, VariantInit},
    },
};

use crate::VariantArgError;
/// 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(i32),
    Bstr(Vec<u16>),
    // BVal(Vec<u8>),
    // LongLong(i64),
    // Long(i32),
    // Short(i16),
    // Float(f32),
    // Double(f64),
    // Scode(i32),
    // CY(i64),
    // Date(f64),
    // CVal(i8),
    // UShort(u16),
    // ULong(u32),
    // ULongLong(u64),
    Int(i32),
    UInt(u32),
}

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 Into<VARIANT> for VariantArg {
    fn into(self) -> VARIANT {
        let mut v = VARIANT::default();
        unsafe {
            VariantInit(&mut v);
        }
        match &self {
            VariantArg::Bstr(bstr) => unsafe {
                let bstr_ptr = SysAllocStringLen(bstr.as_ptr(), bstr.len() as UINT);
                let n2 = v.n1.n2_mut();
                n2.vt = VT_BSTR as u16;
                let _val = n2.n3.bstrVal_mut();
                *_val = bstr_ptr;
                println!("assigning BSTR: {:?}", _val);
            },
            VariantArg::Int(value) => unsafe {
                let n2 = v.n1.n2_mut();
                n2.vt = VT_INT as u16;
                let _val = n2.n3.intVal_mut();
                *_val = *value;
            },
            VariantArg::UInt(value) => unsafe {
                let n2 = v.n1.n2_mut();
                n2.vt = VT_UINT as u16;
                let _val = n2.n3.uintVal_mut();
                *_val = *value;
            },
        }
        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!(format!("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!(format!("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!(format!("expected {:}, got {:}", src, _arg));
        }
    } else {
        panic!(format!("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!(format!("expected {:}, got {:}", src, _arg));
        }
    } else {
        panic!(format!("expected argument to be Uint, got {:?}", _arg));
    }
}