use crate::safearray::SafeArrayAccessor;
use crate::{
WMIError, WMIResult, result_enumerator::IWbemClassWrapper, safearray::safe_array_to_vec,
};
use serde::Serialize;
use std::convert::TryFrom;
use std::ptr::NonNull;
use windows::Win32::Foundation::{VARIANT_FALSE, VARIANT_TRUE};
use windows::Win32::System::Ole::SafeArrayCreateVector;
use windows::Win32::System::Variant::*;
use windows::Win32::System::Variant::{VARIANT, VT_NULL};
use windows::Win32::System::Wmi::{self, CIMTYPE_ENUMERATION, IWbemClassObject};
use windows::core::{IUnknown, Interface, PCWSTR};
fn variant_from_string_array(array: &[String]) -> WMIResult<VARIANT> {
let v: Vec<Vec<u16>> = array
.iter()
.map(|s| s.encode_utf16().chain([0]).collect())
.collect();
let v: Vec<_> = v
.iter()
.map(|b| unsafe { PCWSTR::from_raw(b.as_ptr()) })
.collect();
let variant = unsafe { InitVariantFromStringArray(&v) }?;
Ok(variant)
}
fn set_variant_type(variant: &mut VARIANT, new_type: VARENUM) {
unsafe {
(&mut variant.Anonymous.Anonymous).vt = new_type;
}
}
#[derive(Debug, PartialEq, Serialize, Clone)]
#[serde(untagged)]
pub enum Variant {
Empty,
Null,
String(String),
I1(i8),
I2(i16),
I4(i32),
I8(i64),
R4(f32),
R8(f64),
Bool(bool),
UI1(u8),
UI2(u16),
UI4(u32),
UI8(u64),
Array(Vec<Variant>),
Unknown(IUnknownWrapper),
Object(IWbemClassWrapper),
}
macro_rules! cast_num {
($var:ident, $cim_type: ident) => {
if $cim_type == Wmi::CIM_UINT8 {
Ok(Variant::UI1($var as u8))
} else if $cim_type == Wmi::CIM_UINT16 {
Ok(Variant::UI2($var as u16))
} else if $cim_type == Wmi::CIM_UINT32 {
Ok(Variant::UI4($var as u32))
} else if $cim_type == Wmi::CIM_UINT64 {
Ok(Variant::UI8($var as u64))
} else if $cim_type == Wmi::CIM_SINT8 {
Ok(Variant::I1($var as i8))
} else if $cim_type == Wmi::CIM_SINT16 {
Ok(Variant::I2($var as i16))
} else if $cim_type == Wmi::CIM_SINT32 {
Ok(Variant::I4($var as i32))
} else if $cim_type == Wmi::CIM_SINT64 {
Ok(Variant::I8($var as i64))
} else if $cim_type == Wmi::CIM_REAL32 {
Ok(Variant::R4($var as f32))
} else if $cim_type == Wmi::CIM_REAL64 {
Ok(Variant::R8($var as f64))
} else if $cim_type == Wmi::CIM_CHAR16 {
Ok(Variant::String(String::from_utf16(&[$var as u16])?))
} else {
Err(WMIError::ConvertVariantError(format!(
"Value {:?} cannot be turned into a CIMTYPE {:?}",
$var, $cim_type,
)))
}
};
}
impl Variant {
pub fn from_variant(vt: &VARIANT) -> WMIResult<Variant> {
let variant_type = unsafe { vt.Anonymous.Anonymous.vt };
if variant_type & VT_ARRAY == VT_ARRAY {
let array = NonNull::new(unsafe { vt.Anonymous.Anonymous.Anonymous.parray })
.ok_or(WMIError::NullPointerResult)?;
let item_type = variant_type & VT_TYPEMASK;
return Ok(Variant::Array(unsafe {
safe_array_to_vec(array, item_type)?
}));
}
let variant_value = match variant_type {
VT_BSTR => {
let bstr_ptr = unsafe { &vt.Anonymous.Anonymous.Anonymous.bstrVal };
let bstr_as_str = bstr_ptr.to_string();
Variant::String(bstr_as_str)
}
VT_I1 => {
let num = unsafe { vt.Anonymous.Anonymous.Anonymous.cVal };
Variant::I1(num as _)
}
VT_I2 => {
let num: i16 = unsafe { vt.Anonymous.Anonymous.Anonymous.iVal };
Variant::I2(num)
}
VT_I4 => {
let num: i32 = unsafe { vt.Anonymous.Anonymous.Anonymous.lVal };
Variant::I4(num)
}
VT_I8 => {
let num: i64 = unsafe { vt.Anonymous.Anonymous.Anonymous.llVal };
Variant::I8(num)
}
VT_R4 => {
let num: f32 = unsafe { vt.Anonymous.Anonymous.Anonymous.fltVal };
Variant::R4(num)
}
VT_R8 => {
let num: f64 = unsafe { vt.Anonymous.Anonymous.Anonymous.dblVal };
Variant::R8(num)
}
VT_BOOL => {
let value = unsafe { vt.Anonymous.Anonymous.Anonymous.boolVal };
match value {
VARIANT_FALSE => Variant::Bool(false),
VARIANT_TRUE => Variant::Bool(true),
_ => return Err(WMIError::ConvertBoolError(value.0)),
}
}
VT_UI1 => {
let num: u8 = unsafe { vt.Anonymous.Anonymous.Anonymous.bVal };
Variant::UI1(num)
}
VT_UI2 => {
let num: u16 = unsafe { vt.Anonymous.Anonymous.Anonymous.uiVal };
Variant::UI2(num)
}
VT_UI4 => {
let num: u32 = unsafe { vt.Anonymous.Anonymous.Anonymous.ulVal };
Variant::UI4(num)
}
VT_UI8 => {
let num: u64 = unsafe { vt.Anonymous.Anonymous.Anonymous.ullVal };
Variant::UI8(num)
}
VT_EMPTY => Variant::Empty,
VT_NULL => Variant::Null,
VT_UNKNOWN => {
let ptr = unsafe { vt.Anonymous.Anonymous.Anonymous.punkVal.as_ref() };
let ptr = ptr.cloned().ok_or(WMIError::NullPointerResult)?;
Variant::Unknown(IUnknownWrapper::new(ptr))
}
_ => return Err(WMIError::ConvertError(variant_type.0)),
};
Ok(variant_value)
}
pub fn convert_into_cim_type(self, cim_type: CIMTYPE_ENUMERATION) -> WMIResult<Self> {
if cim_type == Wmi::CIM_EMPTY {
return Ok(Variant::Null);
}
if (Wmi::CIM_FLAG_ARRAY.0 & cim_type.0) != 0 {
return match self {
Variant::Array(arr) => Variant::Array(arr)
.convert_into_cim_type(CIMTYPE_ENUMERATION(cim_type.0 & 0xff)),
Variant::Empty | Variant::Null => Ok(Variant::Array(vec![])),
not_array => {
Ok(Variant::Array(vec![not_array.convert_into_cim_type(
CIMTYPE_ENUMERATION(cim_type.0 & 0xff),
)?]))
}
};
}
let converted_variant = match self {
Variant::Empty => Variant::Empty,
Variant::Null => Variant::Null,
Variant::I1(n) => cast_num!(n, cim_type)?,
Variant::I2(n) => cast_num!(n, cim_type)?,
Variant::I4(n) => cast_num!(n, cim_type)?,
Variant::I8(n) => cast_num!(n, cim_type)?,
Variant::R4(f) => cast_num!(f, cim_type)?,
Variant::R8(f) => cast_num!(f, cim_type)?,
Variant::UI1(n) => cast_num!(n, cim_type)?,
Variant::UI2(n) => cast_num!(n, cim_type)?,
Variant::UI4(n) => cast_num!(n, cim_type)?,
Variant::UI8(n) => cast_num!(n, cim_type)?,
Variant::Bool(b) => {
if cim_type == Wmi::CIM_BOOLEAN {
Variant::Bool(b)
} else {
return Err(WMIError::ConvertVariantError(format!(
"A boolean Variant cannot be turned into a CIMTYPE {:?}",
cim_type,
)));
}
}
Variant::String(s) => {
match cim_type {
Wmi::CIM_STRING | Wmi::CIM_CHAR16 => Variant::String(s),
Wmi::CIM_REAL64 => Variant::R8(s.parse()?),
Wmi::CIM_REAL32 => Variant::R4(s.parse()?),
Wmi::CIM_UINT64 => Variant::UI8(s.parse()?),
Wmi::CIM_SINT64 => Variant::I8(s.parse()?),
Wmi::CIM_UINT32 => Variant::UI4(s.parse()?),
Wmi::CIM_SINT32 => Variant::I4(s.parse()?),
Wmi::CIM_UINT16 => Variant::UI2(s.parse()?),
Wmi::CIM_SINT16 => Variant::I2(s.parse()?),
Wmi::CIM_UINT8 => Variant::UI1(s.parse()?),
Wmi::CIM_SINT8 => Variant::I1(s.parse()?),
_ => Variant::String(s),
}
}
Variant::Array(variants) => {
let converted_variants = variants
.into_iter()
.map(|variant| variant.convert_into_cim_type(cim_type))
.collect::<Result<Vec<_>, WMIError>>()?;
Variant::Array(converted_variants)
}
Variant::Unknown(u) => {
if cim_type == Wmi::CIM_OBJECT {
Variant::Object(u.to_wbem_class_obj()?)
} else {
return Err(WMIError::ConvertVariantError(format!(
"A unknown Variant cannot be turned into a CIMTYPE {:?}",
cim_type,
)));
}
}
Variant::Object(o) => Variant::Object(o),
};
Ok(converted_variant)
}
}
impl TryFrom<Variant> for VARIANT {
type Error = WMIError;
fn try_from(value: Variant) -> WMIResult<VARIANT> {
match value {
Variant::Empty => Ok(VARIANT::default()),
Variant::String(string) => Ok(VARIANT::from(string.as_str())),
Variant::I1(int8) => Ok(VARIANT::from(int8 as i16)),
Variant::I2(int16) => Ok(VARIANT::from(int16)),
Variant::I4(int32) => Ok(VARIANT::from(int32)),
Variant::I8(int64) => Ok(VARIANT::from(int64.to_string().as_str())),
Variant::R4(float32) => Ok(VARIANT::from(float32)),
Variant::R8(float64) => Ok(VARIANT::from(float64)),
Variant::Bool(b) => Ok(VARIANT::from(b)),
Variant::UI1(uint8) => Ok(VARIANT::from(uint8)),
Variant::UI2(uint16) => Ok(VARIANT::from(uint16 as i32)),
Variant::UI4(uint32) => Ok(VARIANT::from(uint32 as i32)),
Variant::UI8(uint64) => Ok(VARIANT::from(uint64.to_string().as_str())),
Variant::Object(instance) => Ok(VARIANT::from(IUnknown::from(instance.inner))),
Variant::Unknown(unknown) => Ok(VARIANT::from(unknown.inner)),
Variant::Null => {
let mut variant = VARIANT::default();
set_variant_type(&mut variant, VT_NULL);
Ok(variant)
}
Variant::Array(array) => {
match array.first() {
None => Ok(Variant::Null.try_into()?),
Some(Variant::UI1(_)) => {
let v: Vec<u8> = Variant::Array(array).try_into()?;
let variant =
unsafe { InitVariantFromBuffer(v.as_ptr() as _, v.len() as _) }?;
Ok(variant)
}
Some(Variant::UI2(_)) => {
let v: Vec<u16> = Variant::Array(array).try_into()?;
let v: Vec<i32> = v.into_iter().map(i32::from).collect();
let variant = unsafe { InitVariantFromInt32Array(&v) }?;
Ok(variant)
}
Some(Variant::UI4(_)) => {
let v: Vec<u32> = Variant::Array(array).try_into()?;
let v: Vec<i32> = v.into_iter().map(|i| i as _).collect();
let variant = unsafe { InitVariantFromInt32Array(&v) }?;
Ok(variant)
}
Some(Variant::UI8(_)) => {
let v: Vec<u64> = Variant::Array(array).try_into()?;
let v: Vec<String> = v.into_iter().map(|i| i.to_string()).collect();
Ok(variant_from_string_array(&v)?)
}
Some(Variant::I1(_)) => {
let v: Vec<i8> = Variant::Array(array).try_into()?;
let v: Vec<i16> = v.into_iter().map(i16::from).collect();
let variant = unsafe { InitVariantFromInt16Array(&v) }?;
Ok(variant)
}
Some(Variant::I2(_)) => {
let v: Vec<i16> = Variant::Array(array).try_into()?;
let variant = unsafe { InitVariantFromInt16Array(&v) }?;
Ok(variant)
}
Some(Variant::I4(_)) => {
let v: Vec<i32> = Variant::Array(array).try_into()?;
let variant = unsafe { InitVariantFromInt32Array(&v) }?;
Ok(variant)
}
Some(Variant::I8(_)) => {
let v: Vec<i64> = Variant::Array(array).try_into()?;
let v: Vec<String> = v.into_iter().map(|i| i.to_string()).collect();
Ok(variant_from_string_array(&v)?)
}
Some(Variant::R4(_)) => {
let v: Vec<f32> = Variant::Array(array).try_into()?;
let safe_arr =
NonNull::new(unsafe { SafeArrayCreateVector(VT_R4, 0, v.len() as _) })
.ok_or(WMIError::NullPointerResult)?;
let mut accessor = unsafe { SafeArrayAccessor::new(safe_arr) }?;
for (src, dst) in v.into_iter().zip(accessor.iter_mut()) {
*dst = src;
}
drop(accessor);
let mut variant = VARIANT::default();
set_variant_type(&mut variant, VT_ARRAY | VT_R4);
unsafe {
(&mut variant.Anonymous.Anonymous).Anonymous.parray = safe_arr.as_ptr();
}
Ok(variant)
}
Some(Variant::R8(_)) => {
let v: Vec<f64> = Variant::Array(array).try_into()?;
let variant = unsafe { InitVariantFromDoubleArray(&v) }?;
Ok(variant)
}
Some(Variant::Bool(_)) => {
let v: Vec<bool> = Variant::Array(array).try_into()?;
let v: Vec<_> = v.into_iter().map(Into::into).collect();
let variant = unsafe { InitVariantFromBooleanArray(&v) }?;
Ok(variant)
}
Some(Variant::String(_)) => {
let v: Vec<String> = Variant::Array(array).try_into()?;
Ok(variant_from_string_array(&v)?)
}
other => Err(WMIError::ConvertVariantError(format!(
"Cannot convert {other:?} to a Windows VARIANT"
))),
}
}
}
}
}
macro_rules! impl_try_from_variant {
($target_type:ty, $variant_type:ident) => {
impl TryFrom<Variant> for $target_type {
type Error = WMIError;
fn try_from(value: Variant) -> Result<$target_type, Self::Error> {
match value {
Variant::$variant_type(item) => Ok(item),
other => Err(WMIError::ConvertVariantError(format!(
"Variant {:?} cannot be turned into a {}",
&other,
stringify!($target_type)
))),
}
}
}
};
}
macro_rules! impl_wrap_type {
($target_type:ty, $variant_type:ident) => {
impl From<$target_type> for Variant {
fn from(value: $target_type) -> Self {
Variant::$variant_type(value)
}
}
};
}
macro_rules! impl_try_vec_from_variant {
($target_type:ty, $variant_type:ident) => {
impl TryFrom<Variant> for Vec<$target_type> {
type Error = WMIError;
fn try_from(value: Variant) -> Result<Vec<$target_type>, Self::Error> {
let array = match value {
Variant::Array(array) => array,
_ => {
return Err(WMIError::ConvertVariantError(format!(
"Cannot convert a non Variant::Array {:?} to Vec",
value
)));
}
};
let mut output_vec = Vec::with_capacity(array.len());
for item in array {
let item = item.try_into()?;
output_vec.push(item);
}
Ok(output_vec)
}
}
};
}
macro_rules! impl_wrap_vec_type {
($target_type:ty, $variant_type:ident) => {
impl From<Vec<$target_type>> for Variant {
fn from(value: Vec<$target_type>) -> Self {
Variant::Array(value.into_iter().map(Variant::$variant_type).collect())
}
}
};
}
macro_rules! bidirectional_variant_convert {
($target_type:ty, $variant_type:ident) => {
impl_try_from_variant!($target_type, $variant_type);
impl_try_vec_from_variant!($target_type, $variant_type);
impl_wrap_type!($target_type, $variant_type);
impl_wrap_vec_type!($target_type, $variant_type);
};
}
bidirectional_variant_convert!(String, String);
bidirectional_variant_convert!(i8, I1);
bidirectional_variant_convert!(i16, I2);
bidirectional_variant_convert!(i32, I4);
bidirectional_variant_convert!(i64, I8);
bidirectional_variant_convert!(u8, UI1);
bidirectional_variant_convert!(u16, UI2);
bidirectional_variant_convert!(u32, UI4);
bidirectional_variant_convert!(u64, UI8);
bidirectional_variant_convert!(f32, R4);
bidirectional_variant_convert!(f64, R8);
bidirectional_variant_convert!(bool, Bool);
bidirectional_variant_convert!(IWbemClassWrapper, Object);
impl From<()> for Variant {
fn from(_value: ()) -> Self {
Variant::Empty
}
}
impl From<&str> for Variant {
fn from(value: &str) -> Self {
Variant::String(value.to_string())
}
}
impl TryFrom<Variant> for () {
type Error = WMIError;
fn try_from(value: Variant) -> Result<(), Self::Error> {
match value {
Variant::Empty => Ok(()),
other => Err(WMIError::ConvertVariantError(format!(
"Variant {:?} cannot be turned into a {}",
&other,
stringify!(())
))),
}
}
}
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct IUnknownWrapper {
inner: IUnknown,
}
impl IUnknownWrapper {
pub fn new(ptr: IUnknown) -> Self {
IUnknownWrapper { inner: ptr }
}
pub fn to_wbem_class_obj(&self) -> WMIResult<IWbemClassWrapper> {
Ok(IWbemClassWrapper {
inner: self.inner.cast::<IWbemClassObject>()?,
})
}
}
impl Serialize for IUnknownWrapper {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_unit()
}
}
#[cfg(test)]
mod tests {
use windows::Win32::System::Wmi::{CIM_SINT8, CIM_SINT64, CIM_UINT16, CIM_UINT32, CIM_UINT64};
use super::*;
#[test]
fn it_convert_into_cim_type_sint8() {
let cim_type = Wmi::CIM_SINT8;
let variant = Variant::I1(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::I1(1));
let variant = Variant::UI1(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::I1(1));
}
#[test]
fn it_convert_into_cim_type_uint8() {
let cim_type = Wmi::CIM_UINT8;
let variant = Variant::UI1(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI1(1));
let variant = Variant::I1(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI1(1));
}
#[test]
fn it_convert_into_cim_type_sint16() {
let cim_type = Wmi::CIM_UINT16;
let variant = Variant::I2(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI2(1));
let variant = Variant::UI2(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI2(1));
let variant = Variant::I1(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI2(1));
}
#[test]
fn it_convert_into_cim_type_uint32() {
let cim_type = Wmi::CIM_UINT32;
let variant = Variant::I8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI4(1));
let variant = Variant::UI8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI4(1));
}
#[test]
fn it_convert_into_cim_type_sint32() {
let cim_type = Wmi::CIM_SINT32;
let variant = Variant::I8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::I4(1));
let variant = Variant::UI8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::I4(1));
let variant = Variant::String("1".to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::I4(1));
}
#[test]
fn it_convert_into_cim_type_uint64() {
let cim_type = Wmi::CIM_UINT64;
let variant = Variant::I8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI8(1));
let variant = Variant::UI8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI8(1));
let variant = Variant::String("1".to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::UI8(1));
}
#[test]
fn it_convert_into_cim_type_sint64() {
let cim_type = Wmi::CIM_SINT64;
let variant = Variant::I8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::I8(1));
let variant = Variant::UI8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::I8(1));
let variant = Variant::String("1".to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::I8(1));
}
#[test]
fn it_convert_into_cim_type_real32() {
let cim_type = Wmi::CIM_REAL32;
let variant = Variant::I8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::R4(1.0));
let variant = Variant::UI8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::R4(1.0));
let variant = Variant::String("1".to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::R4(1.0));
let variant = Variant::String("1.0".to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::R4(1.0));
}
#[test]
fn it_convert_into_cim_type_real64() {
let cim_type = Wmi::CIM_REAL64;
let variant = Variant::I8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::R8(1.0));
let variant = Variant::UI8(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::R8(1.0));
let variant = Variant::String("1".to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::R8(1.0));
let variant = Variant::String("1.0".to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::R8(1.0));
}
#[test]
fn it_convert_into_cim_char16() {
let cim_type = Wmi::CIM_CHAR16;
let variant = Variant::UI2(67);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::String("C".to_string()));
}
#[test]
fn it_convert_into_cim_type_datetime() {
let cim_type = Wmi::CIM_DATETIME;
let datetime = "19980401135809.000000+000";
let variant = Variant::String(datetime.to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::String(datetime.to_string()));
}
#[test]
fn it_convert_into_cim_type_reference() {
let cim_type = Wmi::CIM_REFERENCE;
let datetime =
r#"\\\\PC\\root\\cimv2:Win32_DiskDrive.DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE0\""#;
let variant = Variant::String(datetime.to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::String(datetime.to_string()));
}
#[test]
fn it_convert_an_array_into_cim_type_array() {
let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_UINT64.0 | Wmi::CIM_FLAG_ARRAY.0);
let variant = Variant::Array(vec![Variant::String("1".to_string())]);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::Array(vec![Variant::UI8(1)]));
let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_UINT8.0 | Wmi::CIM_FLAG_ARRAY.0);
let variant = Variant::Array(vec![Variant::UI1(1)]);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::Array(vec![Variant::UI1(1)]));
}
#[test]
fn it_convert_a_single_value_into_cim_type_array() {
let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_UINT64.0 | Wmi::CIM_FLAG_ARRAY.0);
let variant = Variant::String("1".to_string());
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::Array(vec![Variant::UI8(1)]));
let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_UINT8.0 | Wmi::CIM_FLAG_ARRAY.0);
let variant = Variant::UI1(1);
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::Array(vec![Variant::UI1(1)]));
}
#[test]
fn it_convert_an_empty_into_cim_type_array() {
let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_STRING.0 | Wmi::CIM_FLAG_ARRAY.0);
let variant = Variant::Null;
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::Array(vec![]));
let variant = Variant::Empty;
let converted = variant.convert_into_cim_type(cim_type).unwrap();
assert_eq!(converted, Variant::Array(vec![]));
}
#[test]
fn it_bidirectional_string_convert() {
let string = "Test String".to_string();
let variant = Variant::from(string.clone());
assert_eq!(variant.try_into().ok(), Some(string.clone()));
let variant = Variant::from(string.clone());
let ms_variant = VARIANT::try_from(variant).unwrap();
let variant = Variant::from(string.clone());
assert_eq!(Variant::from_variant(&ms_variant).unwrap(), variant);
}
#[test]
fn it_bidirectional_empty_convert() {
let variant = Variant::from(());
assert_eq!(variant.try_into().ok(), Some(()));
let variant = Variant::from(());
let ms_variant = VARIANT::try_from(variant).unwrap();
let variant = Variant::from(());
assert_eq!(Variant::from_variant(&ms_variant).unwrap(), variant);
}
#[test]
fn it_bidirectional_r8_convert() {
let num = 0.123456789;
let variant = Variant::from(num);
assert_eq!(variant.try_into().ok(), Some(num));
let variant = Variant::from(num);
let ms_variant = VARIANT::try_from(variant).unwrap();
let variant = Variant::from(num);
assert_eq!(Variant::from_variant(&ms_variant).unwrap(), variant);
}
#[test]
fn it_convert_array_to_vec() {
let v: Vec<u8> = Variant::Array(vec![Variant::UI1(1), Variant::UI1(2)])
.try_into()
.unwrap();
assert_eq!(v, vec![1, 2]);
let _v: Vec<u16> = Variant::Array(vec![Variant::UI2(1)]).try_into().unwrap();
let _v: Vec<u32> = Variant::Array(vec![Variant::UI4(1)]).try_into().unwrap();
let _v: Vec<u64> = Variant::Array(vec![Variant::UI8(1)]).try_into().unwrap();
let _v: Vec<i8> = Variant::Array(vec![Variant::I1(1)]).try_into().unwrap();
let _v: Vec<i16> = Variant::Array(vec![Variant::I2(1)]).try_into().unwrap();
let _v: Vec<i32> = Variant::Array(vec![Variant::I4(1)]).try_into().unwrap();
let _v: Vec<i64> = Variant::Array(vec![Variant::I8(1)]).try_into().unwrap();
let _v: Vec<f32> = Variant::Array(vec![Variant::R4(1.)]).try_into().unwrap();
let _v: Vec<f64> = Variant::Array(vec![Variant::R8(1.)]).try_into().unwrap();
let _v: Vec<String> = Variant::Array(vec![Variant::String("s".to_string())])
.try_into()
.unwrap();
let _v: Vec<bool> = Variant::Array(vec![Variant::Bool(true)])
.try_into()
.unwrap();
}
#[test]
fn it_convert_array_to_ms_variant() {
let variant = Variant::Array(vec![Variant::UI1(1), Variant::UI1(2)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::UI2(1), Variant::UI2(2)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant)
.unwrap()
.convert_into_cim_type(CIM_UINT16)
.unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::UI4(1), Variant::UI4(2)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant)
.unwrap()
.convert_into_cim_type(CIM_UINT32)
.unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::UI8(1), Variant::UI8(2)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant)
.unwrap()
.convert_into_cim_type(CIM_UINT64)
.unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::I2(1), Variant::I2(2)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::I4(1), Variant::I4(2)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::I8(1), Variant::I8(2)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant)
.unwrap()
.convert_into_cim_type(CIM_SINT64)
.unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::R8(1.), Variant::R8(2.)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::Bool(true), Variant::Bool(false)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![
Variant::String("a".to_string()),
Variant::String("b".to_string()),
]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
assert_eq!(converted_back_variant, Variant::Null);
let variant = Variant::Array(vec![Variant::I1(0), Variant::I1(1)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant)
.unwrap()
.convert_into_cim_type(CIM_SINT8)
.unwrap();
assert_eq!(variant, converted_back_variant);
let variant = Variant::Array(vec![Variant::R4(0.), Variant::R4(1.)]);
let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
assert_eq!(variant, converted_back_variant);
}
#[test]
fn it_does_not_convert_array_to_unsupported_ms_variant() {
let variant = Variant::Array(vec![Variant::String("a".to_string()), Variant::I8(0)]);
assert!(
VARIANT::try_from(variant.clone()).is_err(),
"Mixed arrays are not supported"
);
}
}