1use std::{any::type_name, fmt::Display};
4
5use crate::{Variant, WMIConnection, WMIError, result_enumerator::IWbemClassWrapper};
6use serde::{
7 Serialize, Serializer,
8 ser::{Impossible, SerializeSeq, SerializeStruct},
9};
10use thiserror::Error;
11
12macro_rules! serialize_variant_err_stub {
13 ($signature:ident, $type:ty) => {
14 fn $signature(self, _v: $type) -> Result<Self::Ok, Self::Error> {
15 Err(VariantSerializerError::UnsupportedVariantType(
16 type_name::<$type>().to_string(),
17 ))
18 }
19 };
20}
21
22macro_rules! serialize_variant {
23 ($signature:ident, $type:ty) => {
24 fn $signature(self, v: $type) -> Result<Self::Ok, Self::Error> {
25 Ok(Variant::from(v))
26 }
27 };
28}
29
30pub(crate) struct VariantSerializer<'a> {
31 pub(crate) wmi: &'a WMIConnection,
32 pub(crate) instance: Option<IWbemClassWrapper>,
33}
34
35impl<'a> Serializer for VariantSerializer<'a> {
36 type Ok = Variant;
37 type Error = VariantSerializerError;
38
39 type SerializeSeq = VariantSeqSerializer<'a>;
40 type SerializeTuple = Impossible<Self::Ok, Self::Error>;
41 type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
42 type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
43 type SerializeMap = Impossible<Self::Ok, Self::Error>;
44 type SerializeStruct = VariantInstanceSerializer<'a>;
45 type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
46
47 serialize_variant!(serialize_bool, bool);
48 serialize_variant!(serialize_i8, i8);
49 serialize_variant!(serialize_i16, i16);
50 serialize_variant!(serialize_i32, i32);
51 serialize_variant!(serialize_i64, i64);
52 serialize_variant!(serialize_u8, u8);
53 serialize_variant!(serialize_u16, u16);
54 serialize_variant!(serialize_u32, u32);
55 serialize_variant!(serialize_u64, u64);
56 serialize_variant!(serialize_f32, f32);
57 serialize_variant!(serialize_f64, f64);
58
59 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
60 Ok(self.instance.map(Variant::from).unwrap_or(Variant::Empty))
62 }
63
64 fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
65 Ok(Variant::from(v.to_string()))
66 }
67
68 fn serialize_newtype_variant<T>(
69 self,
70 name: &'static str,
71 _variant_index: u32,
72 variant: &'static str,
73 _value: &T,
74 ) -> Result<Self::Ok, Self::Error>
75 where
76 T: ?Sized + Serialize,
77 {
78 Err(VariantSerializerError::UnsupportedVariantType(format!(
79 "{variant}::{name}"
80 )))
81 }
82
83 fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
84 let ser = self.serialize_struct(name, 0)?;
85
86 ser.end()
87 }
88
89 fn serialize_newtype_struct<T>(
90 self,
91 _name: &'static str,
92 value: &T,
93 ) -> Result<Self::Ok, Self::Error>
94 where
95 T: ?Sized + Serialize,
96 {
97 value.serialize(self)
98 }
99
100 fn serialize_unit_variant(
101 self,
102 _name: &'static str,
103 _variant_index: u32,
104 variant: &'static str,
105 ) -> Result<Self::Ok, Self::Error> {
106 Ok(Variant::from(variant.to_string()))
107 }
108
109 serialize_variant_err_stub!(serialize_char, char);
112 serialize_variant_err_stub!(serialize_bytes, &[u8]);
113
114 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
115 Ok(Variant::Null)
118 }
119
120 fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
121 where
122 T: ?Sized + Serialize,
123 {
124 value.serialize(self)
125 }
126
127 fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
128 Ok(VariantSeqSerializer {
129 seq: Vec::with_capacity(len.unwrap_or_default()),
130 wmi: self.wmi,
131 })
132 }
133
134 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
135 Err(VariantSerializerError::UnsupportedVariantType(
136 "Tuple".to_string(),
137 ))
138 }
139
140 fn serialize_tuple_struct(
141 self,
142 name: &'static str,
143 _len: usize,
144 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
145 Err(VariantSerializerError::UnsupportedVariantType(
146 name.to_string(),
147 ))
148 }
149
150 fn serialize_tuple_variant(
151 self,
152 name: &'static str,
153 _variant_index: u32,
154 variant: &'static str,
155 _len: usize,
156 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
157 Err(VariantSerializerError::UnsupportedVariantType(format!(
158 "{variant}::{name}"
159 )))
160 }
161
162 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
163 Err(VariantSerializerError::UnsupportedVariantType(
164 "Map".to_string(),
165 ))
166 }
167
168 fn serialize_struct(
169 self,
170 name: &'static str,
171 _len: usize,
172 ) -> Result<Self::SerializeStruct, Self::Error> {
173 let instance = match self.instance {
177 Some(instance) => instance,
178 None => self.wmi.get_object(name)?.spawn_instance()?,
179 };
180
181 let ser = VariantInstanceSerializer {
182 wmi: self.wmi,
183 instance,
184 };
185
186 Ok(ser)
187 }
188
189 fn serialize_struct_variant(
190 self,
191 name: &'static str,
192 _variant_index: u32,
193 variant: &'static str,
194 _len: usize,
195 ) -> Result<Self::SerializeStructVariant, Self::Error> {
196 Err(VariantSerializerError::UnsupportedVariantType(format!(
197 "{variant}::{name}"
198 )))
199 }
200}
201
202#[derive(Debug, Error)]
203pub enum VariantSerializerError {
204 #[error("Unknown error while serializing struct:\n{0}")]
205 Unknown(String),
206 #[error("{0} cannot be serialized to a Variant.")]
207 UnsupportedVariantType(String),
208 #[error("WMI error while serializing struct: \n {0}")]
209 WMIError(#[from] WMIError),
210}
211
212impl serde::ser::Error for VariantSerializerError {
213 fn custom<T>(msg: T) -> Self
214 where
215 T: Display,
216 {
217 VariantSerializerError::Unknown(msg.to_string())
218 }
219}
220
221pub(crate) struct VariantInstanceSerializer<'a> {
222 instance: IWbemClassWrapper,
223 wmi: &'a WMIConnection,
224}
225
226impl<'a> SerializeStruct for VariantInstanceSerializer<'a> {
227 type Ok = Variant;
228
229 type Error = VariantSerializerError;
230
231 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
232 where
233 T: ?Sized + Serialize,
234 {
235 let variant = value.serialize(VariantSerializer {
236 wmi: self.wmi,
237 instance: None,
238 })?;
239
240 self.instance.put_property(key, variant)?;
241
242 Ok(())
243 }
244
245 fn end(self) -> Result<Self::Ok, Self::Error> {
246 Ok(Variant::Object(self.instance))
247 }
248}
249
250pub(crate) struct VariantSeqSerializer<'a> {
251 seq: Vec<Variant>,
252 wmi: &'a WMIConnection,
253}
254
255impl<'a> SerializeSeq for VariantSeqSerializer<'a> {
256 type Ok = Variant;
257 type Error = VariantSerializerError;
258
259 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
260 where
261 T: ?Sized + Serialize,
262 {
263 let variant = value.serialize(VariantSerializer {
264 wmi: self.wmi,
265 instance: None,
266 })?;
267
268 self.seq.push(variant);
269
270 Ok(())
271 }
272
273 fn end(self) -> Result<Self::Ok, Self::Error> {
274 Ok(Variant::Array(self.seq))
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281 use crate::tests::fixtures::wmi_con;
282 use serde::Serialize;
283 use std::ptr;
284 use windows::Win32::System::Wmi::{CIM_FLAG_ARRAY, CIM_SINT64, CIM_UINT64};
285 use windows::core::HSTRING;
286
287 #[test]
288 fn it_serialize_instance() {
289 let wmi_con = wmi_con();
290
291 #[derive(Serialize)]
292 struct GetBinaryValue {
293 sSubKeyName: String,
294 sValueName: String,
295 }
296
297 let in_params = GetBinaryValue {
298 sSubKeyName: r#"SYSTEM\CurrentControlSet\Control\Windows"#.to_string(),
299 sValueName: "FullProcessInformationSID".to_string(),
300 };
301
302 let method_instance = wmi_con
304 .get_object("StdRegProv")
305 .unwrap()
306 .get_method("GetBinaryValue")
307 .unwrap()
308 .unwrap()
309 .spawn_instance()
310 .unwrap();
311
312 let instance_from_ser = in_params
313 .serialize(VariantSerializer {
314 wmi: &wmi_con,
315 instance: Some(method_instance),
316 })
317 .unwrap();
318
319 let instance_from_ser = match instance_from_ser {
320 Variant::Object(instance_from_ser) => instance_from_ser,
321 _ => panic!("Unexpected value {:?}", instance_from_ser),
322 };
323
324 let expected_instance = wmi_con
325 .get_object("StdRegProv")
326 .unwrap()
327 .get_method("GetBinaryValue")
328 .unwrap()
329 .unwrap()
330 .spawn_instance()
331 .unwrap();
332
333 assert_eq!(
334 instance_from_ser.class().unwrap(),
335 expected_instance.class().unwrap()
336 );
337
338 assert_eq!(
339 instance_from_ser.get_property("sSubKeyName").unwrap(),
340 Variant::String(in_params.sSubKeyName)
341 );
342 }
343
344 fn spawn_instance(name: &str) -> IWbemClassWrapper {
345 let wmi_con = wmi_con();
346 wmi_con.get_object(&name).unwrap().spawn_instance().unwrap()
347 }
348
349 #[test]
350 fn it_can_get_and_put_strings() {
351 let prop = spawn_instance("Win32_PnPDevicePropertyString");
352 let test_value = Variant::String("Some Title".to_string());
353
354 prop.put_property("Data", test_value.clone()).unwrap();
355 assert_eq!(prop.get_property("Data").unwrap(), test_value,);
356
357 let prop = spawn_instance("Win32_PnPDevicePropertyStringArray");
358 let test_value = Variant::Array(vec![
359 Variant::String("X".to_string()),
360 Variant::String("a".to_string()),
361 ]);
362 prop.put_property("Data", test_value.clone()).unwrap();
363 assert_eq!(prop.get_property("Data").unwrap(), test_value,);
364 }
365
366 #[test]
367 fn it_can_get_and_put_numbers_and_bool() {
368 let prop = spawn_instance("Win32_PnPDevicePropertyBoolean");
369 prop.put_property("Data", true).unwrap();
370 assert_eq!(prop.get_property("Data").unwrap(), Variant::Bool(true));
371
372 let prop = spawn_instance("Win32_PnPDevicePropertyUint8");
373 prop.put_property("Data", u8::MAX).unwrap();
374 assert_eq!(prop.get_property("Data").unwrap(), Variant::UI1(u8::MAX));
375
376 let prop = spawn_instance("Win32_PnPDevicePropertyUint16");
377 prop.put_property("Data", u16::MAX).unwrap();
378 assert_eq!(prop.get_property("Data").unwrap(), Variant::UI2(u16::MAX));
379
380 let prop = spawn_instance("Win32_PnPDevicePropertyUint32");
381 prop.put_property("Data", u32::MAX).unwrap();
382 assert_eq!(prop.get_property("Data").unwrap(), Variant::UI4(u32::MAX));
383
384 let prop = spawn_instance("Win32_PnPDevicePropertyUint64");
385 prop.put_property("Data", u64::MAX).unwrap();
386 assert_eq!(prop.get_property("Data").unwrap(), Variant::UI8(u64::MAX));
387
388 let prop = spawn_instance("Win32_PnPDevicePropertySint8");
389 prop.put_property("Data", i8::MAX).unwrap();
390 assert_eq!(prop.get_property("Data").unwrap(), Variant::I1(i8::MAX));
391 prop.put_property("Data", i8::MIN).unwrap();
392 assert_eq!(prop.get_property("Data").unwrap(), Variant::I1(i8::MIN));
393
394 let prop = spawn_instance("Win32_PnPDevicePropertySint16");
395 prop.put_property("Data", i16::MAX).unwrap();
396 assert_eq!(prop.get_property("Data").unwrap(), Variant::I2(i16::MAX));
397 prop.put_property("Data", i16::MIN).unwrap();
398 assert_eq!(prop.get_property("Data").unwrap(), Variant::I2(i16::MIN));
399
400 let prop = spawn_instance("Win32_PnPDevicePropertySint32");
401 prop.put_property("Data", i32::MAX).unwrap();
402 assert_eq!(prop.get_property("Data").unwrap(), Variant::I4(i32::MAX));
403 prop.put_property("Data", i32::MIN).unwrap();
404 assert_eq!(prop.get_property("Data").unwrap(), Variant::I4(i32::MIN));
405
406 let prop = spawn_instance("Win32_PnPDevicePropertySint64");
407 prop.put_property("Data", i64::MAX).unwrap();
408 assert_eq!(prop.get_property("Data").unwrap(), Variant::I8(i64::MAX));
409 prop.put_property("Data", i64::MIN).unwrap();
410 assert_eq!(prop.get_property("Data").unwrap(), Variant::I8(i64::MIN));
411
412 let prop = spawn_instance("Win32_PnPDevicePropertyReal32");
413 prop.put_property("Data", 1.0f32).unwrap();
414 assert_eq!(prop.get_property("Data").unwrap(), Variant::R4(1.0));
415
416 let prop = spawn_instance("Win32_PnPDevicePropertyReal64");
417 prop.put_property("Data", 1.0f64).unwrap();
418 assert_eq!(prop.get_property("Data").unwrap(), Variant::R8(1.0));
419 }
420
421 #[test]
422 fn it_can_get_and_put_arrays() {
423 let prop = spawn_instance("Win32_PnPDevicePropertyBooleanArray");
424 let test_value = vec![true, false, true];
425 prop.put_property("Data", test_value.clone()).unwrap();
426 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
427
428 let prop = spawn_instance("Win32_PnPDevicePropertyBooleanArray");
430 let test_value = Variant::Array(vec![]);
431 prop.put_property("Data", test_value.clone()).unwrap();
432 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
433
434 let prop = spawn_instance("Win32_PnPDevicePropertyBinary");
435 let test_value = vec![1u8, 2, u8::MAX];
436 prop.put_property("Data", test_value.clone()).unwrap();
437 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
438
439 let prop = spawn_instance("Win32_PnPDevicePropertyUint16Array");
440 let test_value = vec![1u16, 2, u16::MAX];
441 prop.put_property("Data", test_value.clone()).unwrap();
442 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
443
444 let prop = spawn_instance("Win32_PnPDevicePropertyUint32Array");
445 let test_value = vec![1u32, 2, u32::MAX];
446 prop.put_property("Data", test_value.clone()).unwrap();
447 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
448
449 let prop = spawn_instance("Win32_PnPDevicePropertySint8Array");
450 let test_value = vec![1i8, i8::MIN, i8::MAX];
451 prop.put_property("Data", test_value.clone()).unwrap();
452 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
453
454 let prop = spawn_instance("Win32_PnPDevicePropertySint16Array");
455 let test_value = vec![1i16, i16::MIN, i16::MAX];
456 prop.put_property("Data", test_value.clone()).unwrap();
457 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
458
459 let prop = spawn_instance("Win32_PnPDevicePropertySint32Array");
460 let test_value = vec![1i32, i32::MIN, i32::MAX];
461 prop.put_property("Data", test_value.clone()).unwrap();
462 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
463
464 let prop = spawn_instance("Win32_PnPDevicePropertyReal32Array");
465 let test_value = vec![1.0f32, 2.0, -1.0];
466 prop.put_property("Data", test_value.clone()).unwrap();
467 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
468
469 let prop = spawn_instance("Win32_PnPDevicePropertyReal64Array");
470 let test_value = vec![1.0f64, 2.0, -1.0];
471 prop.put_property("Data", test_value.clone()).unwrap();
472 assert_eq!(prop.get_property("Data").unwrap(), test_value.into());
473 }
474
475 #[test]
476 fn it_can_get_and_put_u64_i64_arrays() {
477 let wmi_con = wmi_con();
481 let new_cls_obj = wmi_con.get_object("").unwrap();
482
483 unsafe {
484 new_cls_obj
485 .inner
486 .Put(
487 &HSTRING::from("uValue"),
488 0,
489 ptr::null(),
490 CIM_UINT64.0 | CIM_FLAG_ARRAY.0,
491 )
492 .unwrap()
493 };
494
495 let test_value = vec![1u64, 2, u64::MAX];
496 new_cls_obj
497 .put_property("uValue", test_value.clone())
498 .unwrap();
499 assert_eq!(
500 new_cls_obj.get_property("uValue").unwrap(),
501 test_value.into()
502 );
503
504 unsafe {
505 new_cls_obj
506 .inner
507 .Put(
508 &HSTRING::from("iValue"),
509 0,
510 ptr::null(),
511 CIM_SINT64.0 | CIM_FLAG_ARRAY.0,
512 )
513 .unwrap()
514 };
515
516 let test_value = vec![1i64, i64::MIN, i64::MAX];
517 new_cls_obj
518 .put_property("iValue", test_value.clone())
519 .unwrap();
520 assert_eq!(
521 new_cls_obj.get_property("iValue").unwrap(),
522 test_value.into()
523 );
524 }
525
526 #[test]
527 fn it_serialize_instance_nested() {
528 let wmi_con = wmi_con();
529
530 #[derive(Debug, Serialize, Default)]
531 pub struct Win32_ProcessStartup {
532 pub Title: String,
533 pub ShowWindow: Option<u16>,
534 pub CreateFlags: Option<u32>,
535 }
536
537 #[derive(Serialize)]
538 struct CreateInput {
539 CommandLine: String,
540 ProcessStartupInformation: Win32_ProcessStartup,
541 }
542
543 let startup_info = Win32_ProcessStartup {
545 Title: "Pong".to_string(),
546 ShowWindow: Some(3),
547 CreateFlags: None,
548 };
549
550 let startup_info_instance = startup_info
551 .serialize(VariantSerializer {
552 wmi: &wmi_con,
553 instance: None,
554 })
555 .unwrap();
556
557 let startup_info_instance = match startup_info_instance {
558 Variant::Object(startup_info_instance) => startup_info_instance,
559 _ => panic!("Unexpected value {:?}", startup_info_instance),
560 };
561
562 assert_eq!(
563 startup_info_instance.class().unwrap(),
564 "Win32_ProcessStartup"
565 );
566 assert_eq!(
567 startup_info_instance.get_property("Title").unwrap(),
568 Variant::String(startup_info.Title.clone())
569 );
570
571 assert_eq!(
572 startup_info_instance.get_property("ShowWindow").unwrap(),
573 Variant::UI2(3)
574 );
575 assert_eq!(
576 startup_info_instance.get_property("CreateFlags").unwrap(),
577 Variant::Null
578 );
579
580 let create_params = CreateInput {
581 CommandLine: r#"ping -n 3 127.0.0.1"#.to_string(),
582 ProcessStartupInformation: startup_info,
583 };
584
585 let (method_in, method_out) = wmi_con
587 .get_object("Win32_Process")
588 .unwrap()
589 .get_method_in_out("Create")
590 .unwrap();
591
592 let method_in = method_in.unwrap().spawn_instance().unwrap();
593 let method_out = method_out.unwrap().spawn_instance().unwrap();
594
595 let instance_from_ser = create_params
596 .serialize(VariantSerializer {
597 wmi: &wmi_con,
598 instance: Some(method_in),
599 })
600 .unwrap();
601
602 let instance_from_ser = match instance_from_ser {
603 Variant::Object(instance_from_ser) => instance_from_ser,
604 _ => panic!("Unexpected value {:?}", instance_from_ser),
605 };
606
607 assert_eq!(
608 instance_from_ser.get_property("CommandLine").unwrap(),
609 Variant::String(create_params.CommandLine)
610 );
611
612 assert!(matches!(
613 instance_from_ser
614 .get_property("ProcessStartupInformation")
615 .unwrap(),
616 Variant::Object(_)
617 ));
618
619 assert_eq!(
620 method_out.get_property("ReturnValue").unwrap(),
621 Variant::Null
622 );
623 }
624}