1use crate::safearray::SafeArrayAccessor;
2use crate::{
3 WMIError, WMIResult, result_enumerator::IWbemClassWrapper, safearray::safe_array_to_vec,
4};
5use serde::Serialize;
6use std::convert::TryFrom;
7use std::ptr::NonNull;
8use windows::Win32::Foundation::{VARIANT_FALSE, VARIANT_TRUE};
9use windows::Win32::System::Ole::SafeArrayCreateVector;
10use windows::Win32::System::Variant::*;
11use windows::Win32::System::Variant::{VARIANT, VT_NULL};
12use windows::Win32::System::Wmi::{self, CIMTYPE_ENUMERATION, IWbemClassObject};
13use windows::core::{IUnknown, Interface, PCWSTR};
14
15fn variant_from_string_array(array: &[String]) -> WMIResult<VARIANT> {
16 let v: Vec<Vec<u16>> = array
18 .iter()
19 .map(|s| s.encode_utf16().chain([0]).collect())
20 .collect();
21
22 let v: Vec<_> = v
24 .iter()
25 .map(|b| unsafe { PCWSTR::from_raw(b.as_ptr()) })
26 .collect();
27
28 let variant = unsafe { InitVariantFromStringArray(&v) }?;
31
32 Ok(variant)
33}
34
35fn set_variant_type(variant: &mut VARIANT, new_type: VARENUM) {
36 unsafe {
38 (&mut variant.Anonymous.Anonymous).vt = new_type;
39 }
40}
41
42#[derive(Debug, PartialEq, Serialize, Clone)]
43#[serde(untagged)]
44pub enum Variant {
45 Empty,
46 Null,
47
48 String(String),
49
50 I1(i8),
51 I2(i16),
52 I4(i32),
53 I8(i64),
54
55 R4(f32),
56 R8(f64),
57
58 Bool(bool),
59
60 UI1(u8),
61 UI2(u16),
62 UI4(u32),
63 UI8(u64),
64
65 Array(Vec<Variant>),
66
67 Unknown(IUnknownWrapper),
69 Object(IWbemClassWrapper),
70}
71
72macro_rules! cast_num {
74 ($var:ident, $cim_type: ident) => {
75 if $cim_type == Wmi::CIM_UINT8 {
76 Ok(Variant::UI1($var as u8))
77 } else if $cim_type == Wmi::CIM_UINT16 {
78 Ok(Variant::UI2($var as u16))
79 } else if $cim_type == Wmi::CIM_UINT32 {
80 Ok(Variant::UI4($var as u32))
81 } else if $cim_type == Wmi::CIM_UINT64 {
82 Ok(Variant::UI8($var as u64))
83 } else if $cim_type == Wmi::CIM_SINT8 {
84 Ok(Variant::I1($var as i8))
85 } else if $cim_type == Wmi::CIM_SINT16 {
86 Ok(Variant::I2($var as i16))
87 } else if $cim_type == Wmi::CIM_SINT32 {
88 Ok(Variant::I4($var as i32))
89 } else if $cim_type == Wmi::CIM_SINT64 {
90 Ok(Variant::I8($var as i64))
91 } else if $cim_type == Wmi::CIM_REAL32 {
92 Ok(Variant::R4($var as f32))
93 } else if $cim_type == Wmi::CIM_REAL64 {
94 Ok(Variant::R8($var as f64))
95 } else if $cim_type == Wmi::CIM_CHAR16 {
96 Ok(Variant::String(String::from_utf16(&[$var as u16])?))
97 } else {
98 Err(WMIError::ConvertVariantError(format!(
99 "Value {:?} cannot be turned into a CIMTYPE {:?}",
100 $var, $cim_type,
101 )))
102 }
103 };
104}
105
106impl Variant {
107 pub fn from_variant(vt: &VARIANT) -> WMIResult<Variant> {
112 let variant_type = unsafe { vt.Anonymous.Anonymous.vt };
113
114 if variant_type & VT_ARRAY == VT_ARRAY {
118 let array = NonNull::new(unsafe { vt.Anonymous.Anonymous.Anonymous.parray })
119 .ok_or(WMIError::NullPointerResult)?;
120
121 let item_type = variant_type & VT_TYPEMASK;
122
123 return Ok(Variant::Array(unsafe {
124 safe_array_to_vec(array, item_type)?
125 }));
126 }
127
128 let variant_value = match variant_type {
132 VT_BSTR => {
133 let bstr_ptr = unsafe { &vt.Anonymous.Anonymous.Anonymous.bstrVal };
134 let bstr_as_str = bstr_ptr.to_string();
135 Variant::String(bstr_as_str)
136 }
137 VT_I1 => {
138 let num = unsafe { vt.Anonymous.Anonymous.Anonymous.cVal };
139
140 Variant::I1(num as _)
141 }
142 VT_I2 => {
143 let num: i16 = unsafe { vt.Anonymous.Anonymous.Anonymous.iVal };
144
145 Variant::I2(num)
146 }
147 VT_I4 => {
148 let num: i32 = unsafe { vt.Anonymous.Anonymous.Anonymous.lVal };
149
150 Variant::I4(num)
151 }
152 VT_I8 => {
153 let num: i64 = unsafe { vt.Anonymous.Anonymous.Anonymous.llVal };
154
155 Variant::I8(num)
156 }
157 VT_R4 => {
158 let num: f32 = unsafe { vt.Anonymous.Anonymous.Anonymous.fltVal };
159
160 Variant::R4(num)
161 }
162 VT_R8 => {
163 let num: f64 = unsafe { vt.Anonymous.Anonymous.Anonymous.dblVal };
164
165 Variant::R8(num)
166 }
167 VT_BOOL => {
168 let value = unsafe { vt.Anonymous.Anonymous.Anonymous.boolVal };
169
170 match value {
171 VARIANT_FALSE => Variant::Bool(false),
172 VARIANT_TRUE => Variant::Bool(true),
173 _ => return Err(WMIError::ConvertBoolError(value.0)),
174 }
175 }
176 VT_UI1 => {
177 let num: u8 = unsafe { vt.Anonymous.Anonymous.Anonymous.bVal };
178
179 Variant::UI1(num)
180 }
181 VT_UI2 => {
182 let num: u16 = unsafe { vt.Anonymous.Anonymous.Anonymous.uiVal };
183
184 Variant::UI2(num)
185 }
186 VT_UI4 => {
187 let num: u32 = unsafe { vt.Anonymous.Anonymous.Anonymous.ulVal };
188
189 Variant::UI4(num)
190 }
191 VT_UI8 => {
192 let num: u64 = unsafe { vt.Anonymous.Anonymous.Anonymous.ullVal };
193
194 Variant::UI8(num)
195 }
196 VT_EMPTY => Variant::Empty,
197 VT_NULL => Variant::Null,
198 VT_UNKNOWN => {
199 let ptr = unsafe { vt.Anonymous.Anonymous.Anonymous.punkVal.as_ref() };
200 let ptr = ptr.cloned().ok_or(WMIError::NullPointerResult)?;
201 Variant::Unknown(IUnknownWrapper::new(ptr))
202 }
203 _ => return Err(WMIError::ConvertError(variant_type.0)),
204 };
205
206 Ok(variant_value)
207 }
208
209 pub fn convert_into_cim_type(self, cim_type: CIMTYPE_ENUMERATION) -> WMIResult<Self> {
211 if cim_type == Wmi::CIM_EMPTY {
212 return Ok(Variant::Null);
213 }
214
215 if (Wmi::CIM_FLAG_ARRAY.0 & cim_type.0) != 0 {
216 return match self {
223 Variant::Array(arr) => Variant::Array(arr)
225 .convert_into_cim_type(CIMTYPE_ENUMERATION(cim_type.0 & 0xff)),
226 Variant::Empty | Variant::Null => Ok(Variant::Array(vec![])),
227 not_array => {
229 Ok(Variant::Array(vec![not_array.convert_into_cim_type(
230 CIMTYPE_ENUMERATION(cim_type.0 & 0xff),
231 )?]))
232 }
233 };
234 }
235
236 let converted_variant = match self {
239 Variant::Empty => Variant::Empty,
240 Variant::Null => Variant::Null,
241 Variant::I1(n) => cast_num!(n, cim_type)?,
242 Variant::I2(n) => cast_num!(n, cim_type)?,
243 Variant::I4(n) => cast_num!(n, cim_type)?,
244 Variant::I8(n) => cast_num!(n, cim_type)?,
245 Variant::R4(f) => cast_num!(f, cim_type)?,
246 Variant::R8(f) => cast_num!(f, cim_type)?,
247 Variant::UI1(n) => cast_num!(n, cim_type)?,
248 Variant::UI2(n) => cast_num!(n, cim_type)?,
249 Variant::UI4(n) => cast_num!(n, cim_type)?,
250 Variant::UI8(n) => cast_num!(n, cim_type)?,
251 Variant::Bool(b) => {
252 if cim_type == Wmi::CIM_BOOLEAN {
253 Variant::Bool(b)
254 } else {
255 return Err(WMIError::ConvertVariantError(format!(
256 "A boolean Variant cannot be turned into a CIMTYPE {:?}",
257 cim_type,
258 )));
259 }
260 }
261 Variant::String(s) => {
262 match cim_type {
263 Wmi::CIM_STRING | Wmi::CIM_CHAR16 => Variant::String(s),
264 Wmi::CIM_REAL64 => Variant::R8(s.parse()?),
265 Wmi::CIM_REAL32 => Variant::R4(s.parse()?),
266 Wmi::CIM_UINT64 => Variant::UI8(s.parse()?),
267 Wmi::CIM_SINT64 => Variant::I8(s.parse()?),
268 Wmi::CIM_UINT32 => Variant::UI4(s.parse()?),
269 Wmi::CIM_SINT32 => Variant::I4(s.parse()?),
270 Wmi::CIM_UINT16 => Variant::UI2(s.parse()?),
271 Wmi::CIM_SINT16 => Variant::I2(s.parse()?),
272 Wmi::CIM_UINT8 => Variant::UI1(s.parse()?),
273 Wmi::CIM_SINT8 => Variant::I1(s.parse()?),
274 _ => Variant::String(s),
276 }
277 }
278 Variant::Array(variants) => {
279 let converted_variants = variants
280 .into_iter()
281 .map(|variant| variant.convert_into_cim_type(cim_type))
282 .collect::<Result<Vec<_>, WMIError>>()?;
283
284 Variant::Array(converted_variants)
285 }
286 Variant::Unknown(u) => {
287 if cim_type == Wmi::CIM_OBJECT {
288 Variant::Object(u.to_wbem_class_obj()?)
289 } else {
290 return Err(WMIError::ConvertVariantError(format!(
291 "A unknown Variant cannot be turned into a CIMTYPE {:?}",
292 cim_type,
293 )));
294 }
295 }
296 Variant::Object(o) => Variant::Object(o),
297 };
298
299 Ok(converted_variant)
300 }
301}
302
303impl TryFrom<Variant> for VARIANT {
304 type Error = WMIError;
305
306 fn try_from(value: Variant) -> WMIResult<VARIANT> {
307 match value {
311 Variant::Empty => Ok(VARIANT::default()),
312
313 Variant::String(string) => Ok(VARIANT::from(string.as_str())),
314
315 Variant::I1(int8) => Ok(VARIANT::from(int8 as i16)),
317 Variant::I2(int16) => Ok(VARIANT::from(int16)),
318 Variant::I4(int32) => Ok(VARIANT::from(int32)),
319
320 Variant::I8(int64) => Ok(VARIANT::from(int64.to_string().as_str())),
322
323 Variant::R4(float32) => Ok(VARIANT::from(float32)),
324 Variant::R8(float64) => Ok(VARIANT::from(float64)),
325
326 Variant::Bool(b) => Ok(VARIANT::from(b)),
327
328 Variant::UI1(uint8) => Ok(VARIANT::from(uint8)),
329
330 Variant::UI2(uint16) => Ok(VARIANT::from(uint16 as i32)),
332 Variant::UI4(uint32) => Ok(VARIANT::from(uint32 as i32)),
334
335 Variant::UI8(uint64) => Ok(VARIANT::from(uint64.to_string().as_str())),
337
338 Variant::Object(instance) => Ok(VARIANT::from(IUnknown::from(instance.inner))),
339 Variant::Unknown(unknown) => Ok(VARIANT::from(unknown.inner)),
340
341 Variant::Null => {
342 let mut variant = VARIANT::default();
343 set_variant_type(&mut variant, VT_NULL);
344 Ok(variant)
345 }
346 Variant::Array(array) => {
347 match array.first() {
349 None => Ok(Variant::Null.try_into()?),
351 Some(Variant::UI1(_)) => {
352 let v: Vec<u8> = Variant::Array(array).try_into()?;
353
354 let variant =
356 unsafe { InitVariantFromBuffer(v.as_ptr() as _, v.len() as _) }?;
357 Ok(variant)
358 }
359 Some(Variant::UI2(_)) => {
360 let v: Vec<u16> = Variant::Array(array).try_into()?;
361
362 let v: Vec<i32> = v.into_iter().map(i32::from).collect();
364
365 let variant = unsafe { InitVariantFromInt32Array(&v) }?;
366 Ok(variant)
367 }
368 Some(Variant::UI4(_)) => {
369 let v: Vec<u32> = Variant::Array(array).try_into()?;
370
371 let v: Vec<i32> = v.into_iter().map(|i| i as _).collect();
373
374 let variant = unsafe { InitVariantFromInt32Array(&v) }?;
375 Ok(variant)
376 }
377 Some(Variant::UI8(_)) => {
378 let v: Vec<u64> = Variant::Array(array).try_into()?;
379
380 let v: Vec<String> = v.into_iter().map(|i| i.to_string()).collect();
382
383 Ok(variant_from_string_array(&v)?)
384 }
385 Some(Variant::I1(_)) => {
386 let v: Vec<i8> = Variant::Array(array).try_into()?;
387
388 let v: Vec<i16> = v.into_iter().map(i16::from).collect();
390
391 let variant = unsafe { InitVariantFromInt16Array(&v) }?;
392 Ok(variant)
393 }
394 Some(Variant::I2(_)) => {
395 let v: Vec<i16> = Variant::Array(array).try_into()?;
396
397 let variant = unsafe { InitVariantFromInt16Array(&v) }?;
398 Ok(variant)
399 }
400 Some(Variant::I4(_)) => {
401 let v: Vec<i32> = Variant::Array(array).try_into()?;
402
403 let variant = unsafe { InitVariantFromInt32Array(&v) }?;
404 Ok(variant)
405 }
406 Some(Variant::I8(_)) => {
407 let v: Vec<i64> = Variant::Array(array).try_into()?;
408
409 let v: Vec<String> = v.into_iter().map(|i| i.to_string()).collect();
411
412 Ok(variant_from_string_array(&v)?)
413 }
414 Some(Variant::R4(_)) => {
415 let v: Vec<f32> = Variant::Array(array).try_into()?;
416
417 let safe_arr =
418 NonNull::new(unsafe { SafeArrayCreateVector(VT_R4, 0, v.len() as _) })
419 .ok_or(WMIError::NullPointerResult)?;
420
421 let mut accessor = unsafe { SafeArrayAccessor::new(safe_arr) }?;
422
423 for (src, dst) in v.into_iter().zip(accessor.iter_mut()) {
424 *dst = src;
425 }
426
427 drop(accessor);
428
429 let mut variant = VARIANT::default();
430 set_variant_type(&mut variant, VT_ARRAY | VT_R4);
431
432 unsafe {
436 (&mut variant.Anonymous.Anonymous).Anonymous.parray = safe_arr.as_ptr();
437 }
438
439 Ok(variant)
440 }
441 Some(Variant::R8(_)) => {
442 let v: Vec<f64> = Variant::Array(array).try_into()?;
443
444 let variant = unsafe { InitVariantFromDoubleArray(&v) }?;
445 Ok(variant)
446 }
447 Some(Variant::Bool(_)) => {
448 let v: Vec<bool> = Variant::Array(array).try_into()?;
449 let v: Vec<_> = v.into_iter().map(Into::into).collect();
450
451 let variant = unsafe { InitVariantFromBooleanArray(&v) }?;
452 Ok(variant)
453 }
454 Some(Variant::String(_)) => {
455 let v: Vec<String> = Variant::Array(array).try_into()?;
456
457 Ok(variant_from_string_array(&v)?)
458 }
459 other => Err(WMIError::ConvertVariantError(format!(
460 "Cannot convert {other:?} to a Windows VARIANT"
461 ))),
462 }
463 }
464 }
465 }
466}
467
468macro_rules! impl_try_from_variant {
469 ($target_type:ty, $variant_type:ident) => {
470 impl TryFrom<Variant> for $target_type {
471 type Error = WMIError;
472
473 fn try_from(value: Variant) -> Result<$target_type, Self::Error> {
474 match value {
475 Variant::$variant_type(item) => Ok(item),
476 other => Err(WMIError::ConvertVariantError(format!(
477 "Variant {:?} cannot be turned into a {}",
478 &other,
479 stringify!($target_type)
480 ))),
481 }
482 }
483 }
484 };
485}
486
487macro_rules! impl_wrap_type {
489 ($target_type:ty, $variant_type:ident) => {
490 impl From<$target_type> for Variant {
491 fn from(value: $target_type) -> Self {
492 Variant::$variant_type(value)
493 }
494 }
495 };
496}
497
498macro_rules! impl_try_vec_from_variant {
499 ($target_type:ty, $variant_type:ident) => {
500 impl TryFrom<Variant> for Vec<$target_type> {
501 type Error = WMIError;
502
503 fn try_from(value: Variant) -> Result<Vec<$target_type>, Self::Error> {
504 let array = match value {
505 Variant::Array(array) => array,
506 _ => {
507 return Err(WMIError::ConvertVariantError(format!(
508 "Cannot convert a non Variant::Array {:?} to Vec",
509 value
510 )));
511 }
512 };
513
514 let mut output_vec = Vec::with_capacity(array.len());
515
516 for item in array {
517 let item = item.try_into()?;
518 output_vec.push(item);
519 }
520
521 Ok(output_vec)
522 }
523 }
524 };
525}
526
527macro_rules! impl_wrap_vec_type {
529 ($target_type:ty, $variant_type:ident) => {
530 impl From<Vec<$target_type>> for Variant {
531 fn from(value: Vec<$target_type>) -> Self {
532 Variant::Array(value.into_iter().map(Variant::$variant_type).collect())
533 }
534 }
535 };
536}
537
538macro_rules! bidirectional_variant_convert {
540 ($target_type:ty, $variant_type:ident) => {
541 impl_try_from_variant!($target_type, $variant_type);
542 impl_try_vec_from_variant!($target_type, $variant_type);
543 impl_wrap_type!($target_type, $variant_type);
544 impl_wrap_vec_type!($target_type, $variant_type);
545 };
546}
547
548bidirectional_variant_convert!(String, String);
549bidirectional_variant_convert!(i8, I1);
550bidirectional_variant_convert!(i16, I2);
551bidirectional_variant_convert!(i32, I4);
552bidirectional_variant_convert!(i64, I8);
553bidirectional_variant_convert!(u8, UI1);
554bidirectional_variant_convert!(u16, UI2);
555bidirectional_variant_convert!(u32, UI4);
556bidirectional_variant_convert!(u64, UI8);
557bidirectional_variant_convert!(f32, R4);
558bidirectional_variant_convert!(f64, R8);
559bidirectional_variant_convert!(bool, Bool);
560bidirectional_variant_convert!(IWbemClassWrapper, Object);
561
562impl From<()> for Variant {
563 fn from(_value: ()) -> Self {
564 Variant::Empty
565 }
566}
567
568impl From<&str> for Variant {
569 fn from(value: &str) -> Self {
570 Variant::String(value.to_string())
571 }
572}
573
574impl TryFrom<Variant> for () {
575 type Error = WMIError;
576
577 fn try_from(value: Variant) -> Result<(), Self::Error> {
578 match value {
579 Variant::Empty => Ok(()),
580 other => Err(WMIError::ConvertVariantError(format!(
581 "Variant {:?} cannot be turned into a {}",
582 &other,
583 stringify!(())
584 ))),
585 }
586 }
587}
588
589#[repr(transparent)]
593#[derive(Debug, PartialEq, Eq, Clone)]
594pub struct IUnknownWrapper {
595 inner: IUnknown,
596}
597
598impl IUnknownWrapper {
599 pub fn new(ptr: IUnknown) -> Self {
602 IUnknownWrapper { inner: ptr }
603 }
604
605 pub fn to_wbem_class_obj(&self) -> WMIResult<IWbemClassWrapper> {
606 Ok(IWbemClassWrapper {
607 inner: self.inner.cast::<IWbemClassObject>()?,
608 })
609 }
610}
611
612impl Serialize for IUnknownWrapper {
613 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
616 where
617 S: serde::Serializer,
618 {
619 serializer.serialize_unit()
620 }
621}
622
623#[cfg(test)]
624mod tests {
625 use windows::Win32::System::Wmi::{CIM_SINT8, CIM_SINT64, CIM_UINT16, CIM_UINT32, CIM_UINT64};
626
627 use super::*;
628
629 #[test]
630 fn it_convert_into_cim_type_sint8() {
631 let cim_type = Wmi::CIM_SINT8;
632 let variant = Variant::I1(1);
633 let converted = variant.convert_into_cim_type(cim_type).unwrap();
634 assert_eq!(converted, Variant::I1(1));
635
636 let variant = Variant::UI1(1);
637 let converted = variant.convert_into_cim_type(cim_type).unwrap();
638 assert_eq!(converted, Variant::I1(1));
639 }
640
641 #[test]
642 fn it_convert_into_cim_type_uint8() {
643 let cim_type = Wmi::CIM_UINT8;
644 let variant = Variant::UI1(1);
645 let converted = variant.convert_into_cim_type(cim_type).unwrap();
646 assert_eq!(converted, Variant::UI1(1));
647
648 let variant = Variant::I1(1);
649 let converted = variant.convert_into_cim_type(cim_type).unwrap();
650 assert_eq!(converted, Variant::UI1(1));
651 }
652
653 #[test]
654 fn it_convert_into_cim_type_sint16() {
655 let cim_type = Wmi::CIM_UINT16;
656 let variant = Variant::I2(1);
657 let converted = variant.convert_into_cim_type(cim_type).unwrap();
658 assert_eq!(converted, Variant::UI2(1));
659
660 let variant = Variant::UI2(1);
661 let converted = variant.convert_into_cim_type(cim_type).unwrap();
662 assert_eq!(converted, Variant::UI2(1));
663
664 let variant = Variant::I1(1);
665 let converted = variant.convert_into_cim_type(cim_type).unwrap();
666 assert_eq!(converted, Variant::UI2(1));
667 }
668
669 #[test]
670 fn it_convert_into_cim_type_uint32() {
671 let cim_type = Wmi::CIM_UINT32;
672 let variant = Variant::I8(1);
673 let converted = variant.convert_into_cim_type(cim_type).unwrap();
674 assert_eq!(converted, Variant::UI4(1));
675
676 let variant = Variant::UI8(1);
677 let converted = variant.convert_into_cim_type(cim_type).unwrap();
678 assert_eq!(converted, Variant::UI4(1));
679 }
680
681 #[test]
682 fn it_convert_into_cim_type_sint32() {
683 let cim_type = Wmi::CIM_SINT32;
684 let variant = Variant::I8(1);
685 let converted = variant.convert_into_cim_type(cim_type).unwrap();
686 assert_eq!(converted, Variant::I4(1));
687
688 let variant = Variant::UI8(1);
689 let converted = variant.convert_into_cim_type(cim_type).unwrap();
690 assert_eq!(converted, Variant::I4(1));
691
692 let variant = Variant::String("1".to_string());
693 let converted = variant.convert_into_cim_type(cim_type).unwrap();
694 assert_eq!(converted, Variant::I4(1));
695 }
696
697 #[test]
698 fn it_convert_into_cim_type_uint64() {
699 let cim_type = Wmi::CIM_UINT64;
700 let variant = Variant::I8(1);
701 let converted = variant.convert_into_cim_type(cim_type).unwrap();
702 assert_eq!(converted, Variant::UI8(1));
703
704 let variant = Variant::UI8(1);
705 let converted = variant.convert_into_cim_type(cim_type).unwrap();
706 assert_eq!(converted, Variant::UI8(1));
707
708 let variant = Variant::String("1".to_string());
709 let converted = variant.convert_into_cim_type(cim_type).unwrap();
710 assert_eq!(converted, Variant::UI8(1));
711 }
712
713 #[test]
714 fn it_convert_into_cim_type_sint64() {
715 let cim_type = Wmi::CIM_SINT64;
716 let variant = Variant::I8(1);
717 let converted = variant.convert_into_cim_type(cim_type).unwrap();
718 assert_eq!(converted, Variant::I8(1));
719
720 let variant = Variant::UI8(1);
721 let converted = variant.convert_into_cim_type(cim_type).unwrap();
722 assert_eq!(converted, Variant::I8(1));
723
724 let variant = Variant::String("1".to_string());
725 let converted = variant.convert_into_cim_type(cim_type).unwrap();
726 assert_eq!(converted, Variant::I8(1));
727 }
728
729 #[test]
730 fn it_convert_into_cim_type_real32() {
731 let cim_type = Wmi::CIM_REAL32;
732 let variant = Variant::I8(1);
733 let converted = variant.convert_into_cim_type(cim_type).unwrap();
734 assert_eq!(converted, Variant::R4(1.0));
735
736 let variant = Variant::UI8(1);
737 let converted = variant.convert_into_cim_type(cim_type).unwrap();
738 assert_eq!(converted, Variant::R4(1.0));
739
740 let variant = Variant::String("1".to_string());
741 let converted = variant.convert_into_cim_type(cim_type).unwrap();
742 assert_eq!(converted, Variant::R4(1.0));
743
744 let variant = Variant::String("1.0".to_string());
745 let converted = variant.convert_into_cim_type(cim_type).unwrap();
746 assert_eq!(converted, Variant::R4(1.0));
747 }
748
749 #[test]
750 fn it_convert_into_cim_type_real64() {
751 let cim_type = Wmi::CIM_REAL64;
752 let variant = Variant::I8(1);
753 let converted = variant.convert_into_cim_type(cim_type).unwrap();
754 assert_eq!(converted, Variant::R8(1.0));
755
756 let variant = Variant::UI8(1);
757 let converted = variant.convert_into_cim_type(cim_type).unwrap();
758 assert_eq!(converted, Variant::R8(1.0));
759
760 let variant = Variant::String("1".to_string());
761 let converted = variant.convert_into_cim_type(cim_type).unwrap();
762 assert_eq!(converted, Variant::R8(1.0));
763
764 let variant = Variant::String("1.0".to_string());
765 let converted = variant.convert_into_cim_type(cim_type).unwrap();
766 assert_eq!(converted, Variant::R8(1.0));
767 }
768
769 #[test]
770 fn it_convert_into_cim_char16() {
771 let cim_type = Wmi::CIM_CHAR16;
772 let variant = Variant::UI2(67);
773 let converted = variant.convert_into_cim_type(cim_type).unwrap();
774 assert_eq!(converted, Variant::String("C".to_string()));
775 }
776
777 #[test]
778 fn it_convert_into_cim_type_datetime() {
779 let cim_type = Wmi::CIM_DATETIME;
780 let datetime = "19980401135809.000000+000";
781 let variant = Variant::String(datetime.to_string());
782 let converted = variant.convert_into_cim_type(cim_type).unwrap();
783 assert_eq!(converted, Variant::String(datetime.to_string()));
784 }
785
786 #[test]
787 fn it_convert_into_cim_type_reference() {
788 let cim_type = Wmi::CIM_REFERENCE;
789 let datetime =
790 r#"\\\\PC\\root\\cimv2:Win32_DiskDrive.DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE0\""#;
791 let variant = Variant::String(datetime.to_string());
792 let converted = variant.convert_into_cim_type(cim_type).unwrap();
793 assert_eq!(converted, Variant::String(datetime.to_string()));
794 }
795
796 #[test]
797 fn it_convert_an_array_into_cim_type_array() {
798 let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_UINT64.0 | Wmi::CIM_FLAG_ARRAY.0);
799 let variant = Variant::Array(vec![Variant::String("1".to_string())]);
800 let converted = variant.convert_into_cim_type(cim_type).unwrap();
801 assert_eq!(converted, Variant::Array(vec![Variant::UI8(1)]));
802
803 let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_UINT8.0 | Wmi::CIM_FLAG_ARRAY.0);
804 let variant = Variant::Array(vec![Variant::UI1(1)]);
805 let converted = variant.convert_into_cim_type(cim_type).unwrap();
806 assert_eq!(converted, Variant::Array(vec![Variant::UI1(1)]));
807 }
808
809 #[test]
810 fn it_convert_a_single_value_into_cim_type_array() {
811 let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_UINT64.0 | Wmi::CIM_FLAG_ARRAY.0);
812 let variant = Variant::String("1".to_string());
813 let converted = variant.convert_into_cim_type(cim_type).unwrap();
814 assert_eq!(converted, Variant::Array(vec![Variant::UI8(1)]));
815
816 let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_UINT8.0 | Wmi::CIM_FLAG_ARRAY.0);
817 let variant = Variant::UI1(1);
818 let converted = variant.convert_into_cim_type(cim_type).unwrap();
819 assert_eq!(converted, Variant::Array(vec![Variant::UI1(1)]));
820 }
821
822 #[test]
823 fn it_convert_an_empty_into_cim_type_array() {
824 let cim_type = CIMTYPE_ENUMERATION(Wmi::CIM_STRING.0 | Wmi::CIM_FLAG_ARRAY.0);
825 let variant = Variant::Null;
826 let converted = variant.convert_into_cim_type(cim_type).unwrap();
827 assert_eq!(converted, Variant::Array(vec![]));
828
829 let variant = Variant::Empty;
830 let converted = variant.convert_into_cim_type(cim_type).unwrap();
831 assert_eq!(converted, Variant::Array(vec![]));
832 }
833
834 #[test]
835 fn it_bidirectional_string_convert() {
836 let string = "Test String".to_string();
837 let variant = Variant::from(string.clone());
838 assert_eq!(variant.try_into().ok(), Some(string.clone()));
839
840 let variant = Variant::from(string.clone());
841 let ms_variant = VARIANT::try_from(variant).unwrap();
842 let variant = Variant::from(string.clone());
843 assert_eq!(Variant::from_variant(&ms_variant).unwrap(), variant);
844 }
845
846 #[test]
847 fn it_bidirectional_empty_convert() {
848 let variant = Variant::from(());
849 assert_eq!(variant.try_into().ok(), Some(()));
850
851 let variant = Variant::from(());
852 let ms_variant = VARIANT::try_from(variant).unwrap();
853 let variant = Variant::from(());
854 assert_eq!(Variant::from_variant(&ms_variant).unwrap(), variant);
855 }
856
857 #[test]
858 fn it_bidirectional_r8_convert() {
859 let num = 0.123456789;
860 let variant = Variant::from(num);
861 assert_eq!(variant.try_into().ok(), Some(num));
862
863 let variant = Variant::from(num);
864 let ms_variant = VARIANT::try_from(variant).unwrap();
865 let variant = Variant::from(num);
866 assert_eq!(Variant::from_variant(&ms_variant).unwrap(), variant);
867 }
868
869 #[test]
870 fn it_convert_array_to_vec() {
871 let v: Vec<u8> = Variant::Array(vec![Variant::UI1(1), Variant::UI1(2)])
872 .try_into()
873 .unwrap();
874
875 assert_eq!(v, vec![1, 2]);
876
877 let _v: Vec<u16> = Variant::Array(vec![Variant::UI2(1)]).try_into().unwrap();
878 let _v: Vec<u32> = Variant::Array(vec![Variant::UI4(1)]).try_into().unwrap();
879 let _v: Vec<u64> = Variant::Array(vec![Variant::UI8(1)]).try_into().unwrap();
880
881 let _v: Vec<i8> = Variant::Array(vec![Variant::I1(1)]).try_into().unwrap();
882 let _v: Vec<i16> = Variant::Array(vec![Variant::I2(1)]).try_into().unwrap();
883 let _v: Vec<i32> = Variant::Array(vec![Variant::I4(1)]).try_into().unwrap();
884 let _v: Vec<i64> = Variant::Array(vec![Variant::I8(1)]).try_into().unwrap();
885
886 let _v: Vec<f32> = Variant::Array(vec![Variant::R4(1.)]).try_into().unwrap();
887 let _v: Vec<f64> = Variant::Array(vec![Variant::R8(1.)]).try_into().unwrap();
888
889 let _v: Vec<String> = Variant::Array(vec![Variant::String("s".to_string())])
890 .try_into()
891 .unwrap();
892 let _v: Vec<bool> = Variant::Array(vec![Variant::Bool(true)])
893 .try_into()
894 .unwrap();
895 }
896
897 #[test]
898 fn it_convert_array_to_ms_variant() {
899 let variant = Variant::Array(vec![Variant::UI1(1), Variant::UI1(2)]);
900 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
901 let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
902
903 assert_eq!(variant, converted_back_variant);
904
905 let variant = Variant::Array(vec![Variant::UI2(1), Variant::UI2(2)]);
906 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
907 let converted_back_variant = Variant::from_variant(&ms_variant)
908 .unwrap()
909 .convert_into_cim_type(CIM_UINT16)
910 .unwrap();
911
912 assert_eq!(variant, converted_back_variant);
913
914 let variant = Variant::Array(vec![Variant::UI4(1), Variant::UI4(2)]);
915 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
916 let converted_back_variant = Variant::from_variant(&ms_variant)
917 .unwrap()
918 .convert_into_cim_type(CIM_UINT32)
919 .unwrap();
920
921 assert_eq!(variant, converted_back_variant);
922
923 let variant = Variant::Array(vec![Variant::UI8(1), Variant::UI8(2)]);
924 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
925 let converted_back_variant = Variant::from_variant(&ms_variant)
926 .unwrap()
927 .convert_into_cim_type(CIM_UINT64)
928 .unwrap();
929
930 assert_eq!(variant, converted_back_variant);
931
932 let variant = Variant::Array(vec![Variant::I2(1), Variant::I2(2)]);
933 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
934 let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
935
936 assert_eq!(variant, converted_back_variant);
937
938 let variant = Variant::Array(vec![Variant::I4(1), Variant::I4(2)]);
939 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
940 let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
941
942 assert_eq!(variant, converted_back_variant);
943
944 let variant = Variant::Array(vec![Variant::I8(1), Variant::I8(2)]);
945 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
946 let converted_back_variant = Variant::from_variant(&ms_variant)
947 .unwrap()
948 .convert_into_cim_type(CIM_SINT64)
949 .unwrap();
950
951 assert_eq!(variant, converted_back_variant);
952
953 let variant = Variant::Array(vec![Variant::R8(1.), Variant::R8(2.)]);
954 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
955 let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
956
957 assert_eq!(variant, converted_back_variant);
958
959 let variant = Variant::Array(vec![Variant::Bool(true), Variant::Bool(false)]);
960 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
961 let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
962
963 assert_eq!(variant, converted_back_variant);
964
965 let variant = Variant::Array(vec![
966 Variant::String("a".to_string()),
967 Variant::String("b".to_string()),
968 ]);
969 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
970 let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
971
972 assert_eq!(variant, converted_back_variant);
973
974 let variant = Variant::Array(vec![]);
976 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
977 let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
978
979 assert_eq!(converted_back_variant, Variant::Null);
980
981 let variant = Variant::Array(vec![Variant::I1(0), Variant::I1(1)]);
982 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
983 let converted_back_variant = Variant::from_variant(&ms_variant)
984 .unwrap()
985 .convert_into_cim_type(CIM_SINT8)
986 .unwrap();
987 assert_eq!(variant, converted_back_variant);
988
989 let variant = Variant::Array(vec![Variant::R4(0.), Variant::R4(1.)]);
990 let ms_variant = VARIANT::try_from(variant.clone()).unwrap();
991 let converted_back_variant = Variant::from_variant(&ms_variant).unwrap();
992 assert_eq!(variant, converted_back_variant);
993 }
994
995 #[test]
996 fn it_does_not_convert_array_to_unsupported_ms_variant() {
997 let variant = Variant::Array(vec![Variant::String("a".to_string()), Variant::I8(0)]);
998 assert!(
999 VARIANT::try_from(variant.clone()).is_err(),
1000 "Mixed arrays are not supported"
1001 );
1002 }
1003}