diff --git a/proxmox-tools/Cargo.toml b/proxmox-tools/Cargo.toml index c9ee4a93..89dabf36 100644 --- a/proxmox-tools/Cargo.toml +++ b/proxmox-tools/Cargo.toml @@ -23,3 +23,4 @@ valgrind = [ "valgrind_request" ] # Docs should be able to reference the proxmox crate. [dev-dependencies] proxmox = { path = "../proxmox" } +serde_json = "1.0" diff --git a/proxmox-tools/src/serde.rs b/proxmox-tools/src/serde.rs index 26bf618b..45b3ce12 100644 --- a/proxmox-tools/src/serde.rs +++ b/proxmox-tools/src/serde.rs @@ -1,51 +1,79 @@ //! Serialization helpers for serde -/// Sertialize DateTime as RFC3339 +/// Serialize DateTime as RFC3339. +/// +/// Usage example: +/// ``` +/// # pub extern crate proxmox_tools; +/// # mod proxmox { pub use proxmox_tools as tools; } +/// +/// use chrono::{DateTime, TimeZone, Utc}; +/// use serde::{Deserialize, Serialize}; +/// +/// # #[derive(Debug)] +/// #[derive(Deserialize, PartialEq, Serialize)] +/// struct Foo { +/// #[serde(with = "proxmox::tools::serde::date_time_as_rfc3339")] +/// date: DateTime, +/// } +/// +/// let obj = Foo { date: Utc.timestamp_millis(86400000) }; // random test value +/// let json = serde_json::to_string(&obj).unwrap(); +/// assert_eq!(json, r#"{"date":"1970-01-02T00:00:00+00:00"}"#); +/// +/// let deserialized: Foo = serde_json::from_str(&json).unwrap(); +/// assert_eq!(obj, deserialized); +/// ``` pub mod date_time_as_rfc3339 { + use chrono::{DateTime, TimeZone}; + use serde::{Deserialize, Deserializer, Serializer}; - use chrono::{Local, DateTime}; - use serde::{Serializer, Deserializer, Deserialize}; - - pub fn serialize(time: &DateTime, serializer: S) -> Result - where S: Serializer, + pub fn serialize(time: &DateTime, serializer: S) -> Result + where + S: Serializer, + Tz: TimeZone, + Tz::Offset: std::fmt::Display, { serializer.serialize_str(&time.to_rfc3339()) } - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where D: Deserializer<'de> + pub fn deserialize<'de, D, Tz>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + Tz: TimeZone, + DateTime: std::str::FromStr, + as std::str::FromStr>::Err: std::string::ToString, { use serde::de::Error; - String::deserialize(deserializer) - .and_then(|string| { - string.parse::>() - .map_err(|err| Error::custom(err.to_string())) - }) + String::deserialize(deserializer).and_then(|string| { + string + .parse::>() + .map_err(|err| Error::custom(err.to_string())) + }) } } - /// Serialize Vec as base64 encoded string. pub mod bytes_as_base64 { use base64; - use serde::{Serializer,Deserializer, Deserialize}; + use serde::{Deserialize, Deserializer, Serializer}; pub fn serialize(data: &T, serializer: S) -> Result - where T: AsRef<[u8]>, - S: Serializer, + where + T: AsRef<[u8]>, + S: Serializer, { serializer.serialize_str(&base64::encode(data.as_ref())) } pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where D: Deserializer<'de> + where + D: Deserializer<'de>, { use serde::de::Error; - String::deserialize(deserializer) - .and_then(|string| { - base64::decode(&string) - .map_err(|err| Error::custom(err.to_string())) - }) + String::deserialize(deserializer).and_then(|string| { + base64::decode(&string).map_err(|err| Error::custom(err.to_string())) + }) } }