Skip to content

Commit

Permalink
Add a WMIDuration for durations
Browse files Browse the repository at this point in the history
  • Loading branch information
ohadravid committed Jun 4, 2019
1 parent 58d2322 commit 15851de
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wmi"
version = "0.4.1"
version = "0.4.2"
authors = ["Ohad Ravid <[email protected]>"]
edition = "2018"
license = "MIT OR Apache-2.0"
Expand Down
13 changes: 13 additions & 0 deletions src/de/wbem_class_de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
mod tests {
use super::*;
use crate::datetime::WMIDateTime;
use crate::duration::WMIDuration;
use crate::variant::Variant;
use serde::Deserialize;
use std::collections::HashMap;
Expand Down Expand Up @@ -403,6 +404,18 @@ mod tests {
)
}

#[test]
fn it_desr_duration() {
let wmi_con = wmi_con();

#[derive(Deserialize, Debug)]
pub struct Win32_NetworkLoginProfile {
pub PasswordAge: Option<WMIDuration>,
}

let profiles: Vec<Win32_NetworkLoginProfile> = wmi_con.query().unwrap();
}

#[test]
fn it_can_desr_newtype() {
// Values can return as Null / Empty from WMI.
Expand Down
89 changes: 89 additions & 0 deletions src/duration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use chrono::prelude::*;
use failure::{bail, Error};
use serde::{de, ser};
use std::fmt;
use std::str::FromStr;
use std::time::Duration;

/// A wrapper type around Duration, which supports parsing from WMI-format strings.
///
#[derive(Debug)]
pub struct WMIDuration(pub Duration);

impl FromStr for WMIDuration {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() != 25 {
bail!("Expected {:?} to be at 25 chars", s)
}

let (seconds_part, reminder) = s.split_at(14);
let (micros_part, _) = reminder[1..].split_at(6);

let seconds: u64 = seconds_part.parse()?;
let micros: u64 = micros_part.parse()?;

let duration = Duration::from_secs(seconds) + Duration::from_micros(micros);

Ok(Self(duration))
}
}

struct DurationVisitor;

impl<'de> de::Visitor<'de> for DurationVisitor {
type Value = WMIDuration;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a timestamp in WMI format")
}

fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
value.parse().map_err(|err| E::custom(format!("{}", err)))
}
}

impl<'de> de::Deserialize<'de> for WMIDuration {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
deserializer.deserialize_u64(DurationVisitor)
}
}

impl ser::Serialize for WMIDuration {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_u64(self.0.as_micros() as u64)
}
}

#[cfg(test)]
mod tests {
use super::WMIDuration;
use serde_json;

#[test]
fn it_works() {
let duration: WMIDuration = "00000005141436.100001:000".parse().unwrap();

assert_eq!(duration.0.as_micros(), 5141436100001);
assert_eq!(duration.0.as_millis(), 5141436100);
assert_eq!(duration.0.as_secs(), 5141436);
}

#[test]
fn it_serializes_to_rfc() {
let duration: WMIDuration = "00000005141436.100001:000".parse().unwrap();

let v = serde_json::to_string(&duration).unwrap();
assert_eq!(v, "5141436100001");
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
pub mod connection;
pub mod datetime;
pub mod de;
pub mod duration;
pub mod error;
pub mod query;
pub mod result_enumerator;
Expand All @@ -111,4 +112,5 @@ pub mod tests;

pub use connection::{COMLibrary, WMIConnection};
pub use datetime::WMIDateTime;
pub use duration::WMIDuration;
pub use variant::Variant;

0 comments on commit 15851de

Please sign in to comment.