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
//! # win-variant
//!
//! win-variant is a crate to improve the ergonomics of working with VARIANTS
//! from winapi.
//!
//! The crate uses enums and conversion traits to allow for modern rust usage
//! as well as provides utilities to easily free VARIANTS correctly.

mod arg;
mod errors;
mod result;

use winapi::{
    shared::wtypes::{VARENUM, VT_BSTR},
    um::{
        oaidl::VARIANT,
        oleauto::{SysFreeString, VariantClear},
    },
};

pub use arg::VariantArg;
pub use errors::{VariantArgError, VariantResultError};
pub use result::VariantResult;

/// free_variants is a utility to properly free the allocated resources of
/// variants.
pub fn free_variants(variants: &mut Vec<VARIANT>) {
    for variant in variants {
        unsafe {
            free_variant(variant);
        }
    }
}

/// free_variant is a utility to properly free the allocated resources of a
/// variant.
pub unsafe fn free_variant(variant: &mut VARIANT) {
    match variant.n1.n2().vt as VARENUM {
        VT_BSTR => {
            let p = variant.n1.n2_mut().n3.bstrVal();
            println!("freeing BSTR: {:?}", p);
            SysFreeString(*p);
        }
        _ => (),
    };
    VariantClear(variant);
}

#[cfg(test)]
mod tests {
    use crate::{free_variant, VariantArg, VariantResult};
    use std::convert::TryFrom;
    use winapi::um::oaidl::VARIANT;

    #[test]
    fn it_converts_to_result_from_bstr_arg() {
        let src = "Test Value";
        let _arg = VariantArg::try_from(src).unwrap();

        let mut v: VARIANT = _arg.into();
        let result = VariantResult::try_from(v).unwrap();
        unsafe {
            free_variant(&mut v);
        }

        if let VariantResult::String(v) = result {
            if !src.eq(&v) {
                panic!(format!("expected {:?}, got {:?}", src, v));
            }
        } else {
            panic!(format!("expected String, got: {:?}", result));
        }
    }

    #[test]
    fn it_converts_to_result_from_int_arg() {
        let src: i32 = 1234;
        let _arg = VariantArg::from(src);

        let mut v: VARIANT = _arg.into();
        let result = VariantResult::try_from(v).unwrap();
        unsafe {
            free_variant(&mut v);
        }

        if let VariantResult::Int(v) = result {
            if src != v {
                panic!(format!("expected {:}, got {:}", src, v));
            }
        } else {
            panic!(format!("expected Int, got {:?}", result));
        }
    }

    #[test]
    fn it_converts_to_result_from_uint_arg() {
        let src: u32 = 1234;
        let _arg = VariantArg::from(src);

        let mut v: VARIANT = _arg.into();
        let result = VariantResult::try_from(v).unwrap();
        unsafe {
            free_variant(&mut v);
        }

        if let VariantResult::Uint(v) = result {
            if src != v {
                panic!(format!("expected {:}, got {:}", src, v));
            }
        } else {
            panic!(format!("expected Int, got {:?}", result));
        }
    }
}