Initial commit (import code from ruma-client-api)
Co-authored-by: Isaiah Inuwa <isaiah.inuwa@gmail.com>
This commit is contained in:
commit
c0e751669f
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/target
|
||||
|
||||
|
||||
#Added by cargo
|
||||
#
|
||||
#already existing elements were commented out
|
||||
|
||||
#/target
|
||||
Cargo.lock
|
20
Cargo.toml
Normal file
20
Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "ruma-serde"
|
||||
description = "De-/serialization helpers for other ruma crates"
|
||||
documentation = "https://docs.rs/ruma-serde"
|
||||
license = "MIT"
|
||||
authors = [
|
||||
"Jonas Platte <jplatte@posteo.de>",
|
||||
"Isaiah Inuwa <isaiah.inuwa@gmail.com>",
|
||||
]
|
||||
version = "0.1.0"
|
||||
repository = "https://github.com/ruma/ruma-serde"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
js_int = { version = "0.1.4", features = ["serde"] }
|
||||
serde = "1.0.106"
|
||||
serde_json = "1.0.51"
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { version = "1.0.106", features = ["derive"] }
|
4
src/duration.rs
Normal file
4
src/duration.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! De-/serialization functions for `std::time::Duration` objects
|
||||
|
||||
pub mod opt_ms;
|
||||
pub mod secs;
|
102
src/duration/opt_ms.rs
Normal file
102
src/duration/opt_ms.rs
Normal file
@ -0,0 +1,102 @@
|
||||
//! De-/serialization functions for `Option<std::time::Duration>` objects represented as milliseconds.
|
||||
//! Delegates to `js_int::UInt` to ensure integer size is within bounds.
|
||||
|
||||
use std::{convert::TryFrom, time::Duration};
|
||||
|
||||
use js_int::UInt;
|
||||
use serde::{
|
||||
de::{Deserialize, Deserializer},
|
||||
ser::{Error, Serialize, Serializer},
|
||||
};
|
||||
|
||||
/// Serialize an Option<Duration>.
|
||||
///
|
||||
/// Will fail if integer is greater than the maximum integer that can be
|
||||
/// unambiguously represented by an f64.
|
||||
pub fn serialize<S>(opt_duration: &Option<Duration>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match opt_duration {
|
||||
Some(duration) => match UInt::try_from(duration.as_millis()) {
|
||||
Ok(uint) => uint.serialize(serializer),
|
||||
Err(err) => Err(S::Error::custom(err)),
|
||||
},
|
||||
None => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes an Option<Duration>.
|
||||
///
|
||||
/// Will fail if integer is greater than the maximum integer that can be
|
||||
/// unambiguously represented by an f64.
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Duration>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(Option::<UInt>::deserialize(deserializer)?
|
||||
.map(|millis| Duration::from_millis(millis.into())))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
struct DurationTest {
|
||||
#[serde(with = "super", default, skip_serializing_if = "Option::is_none")]
|
||||
timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_some() {
|
||||
let json = json!({ "timeout": 3000 });
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_value::<DurationTest>(json).unwrap(),
|
||||
DurationTest {
|
||||
timeout: Some(Duration::from_millis(3000))
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_none_by_absence() {
|
||||
let json = json!({});
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_value::<DurationTest>(json).unwrap(),
|
||||
DurationTest { timeout: None },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_none_by_null() {
|
||||
let json = json!({ "timeout": null });
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_value::<DurationTest>(json).unwrap(),
|
||||
DurationTest { timeout: None },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_some() {
|
||||
let request = DurationTest {
|
||||
timeout: Some(Duration::new(2, 0)),
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::to_value(&request).unwrap(),
|
||||
json!({ "timeout": 2000 })
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_none() {
|
||||
let request = DurationTest { timeout: None };
|
||||
assert_eq!(serde_json::to_value(&request).unwrap(), json!({}));
|
||||
}
|
||||
}
|
69
src/duration/secs.rs
Normal file
69
src/duration/secs.rs
Normal file
@ -0,0 +1,69 @@
|
||||
//! De-/serialization functions for `Option<std::time::Duration>` objects represented as milliseconds.
|
||||
//! Delegates to `js_int::UInt` to ensure integer size is within bounds.
|
||||
|
||||
use std::{convert::TryFrom, time::Duration};
|
||||
|
||||
use js_int::UInt;
|
||||
use serde::{
|
||||
de::{Deserialize, Deserializer},
|
||||
ser::{Error, Serialize, Serializer},
|
||||
};
|
||||
|
||||
/// Serializes a Duration to an integer representing seconds.
|
||||
///
|
||||
/// Will fail if integer is greater than the maximum integer that can be
|
||||
/// unambiguously represented by an f64.
|
||||
pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match UInt::try_from(duration.as_secs()) {
|
||||
Ok(uint) => uint.serialize(serializer),
|
||||
Err(err) => Err(S::Error::custom(err)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes an integer representing seconds into a Duration.
|
||||
///
|
||||
/// Will fail if integer is greater than the maximum integer that can be
|
||||
/// unambiguously represented by an f64.
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
UInt::deserialize(deserializer).map(|secs| Duration::from_secs(secs.into()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
struct DurationTest {
|
||||
#[serde(with = "super")]
|
||||
timeout: Duration,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize() {
|
||||
let json = json!({ "timeout": 3 });
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_value::<DurationTest>(json).unwrap(),
|
||||
DurationTest {
|
||||
timeout: Duration::from_secs(3)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize() {
|
||||
let test = DurationTest {
|
||||
timeout: Duration::from_millis(7000),
|
||||
};
|
||||
assert_eq!(serde_json::to_value(test).unwrap(), json!({ "timeout": 7 }),);
|
||||
}
|
||||
}
|
24
src/json_string.rs
Normal file
24
src/json_string.rs
Normal file
@ -0,0 +1,24 @@
|
||||
//! De-/serialization functions to and from json strings, allows the type to be used as a query string.
|
||||
|
||||
use serde::{
|
||||
de::{Deserialize, DeserializeOwned, Deserializer, Error as _},
|
||||
ser::{Error as _, Serialize, Serializer},
|
||||
};
|
||||
|
||||
pub fn serialize<T, S>(filter: T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
S: Serializer,
|
||||
{
|
||||
let json = serde_json::to_string(&filter).map_err(S::Error::custom)?;
|
||||
serializer.serialize_str(&json)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
serde_json::from_str(&s).map_err(D::Error::custom)
|
||||
}
|
9
src/lib.rs
Normal file
9
src/lib.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//! De-/serialization helpers for other ruma crates
|
||||
|
||||
pub mod duration;
|
||||
pub mod json_string;
|
||||
pub mod time;
|
||||
|
||||
pub fn is_default<T: Default + PartialEq>(val: &T) -> bool {
|
||||
val == &T::default()
|
||||
}
|
4
src/time.rs
Normal file
4
src/time.rs
Normal file
@ -0,0 +1,4 @@
|
||||
//! De-/serialization functions for `std::time::SystemTime` objects
|
||||
|
||||
pub mod ms_since_unix_epoch;
|
||||
pub mod opt_ms_since_unix_epoch;
|
78
src/time/ms_since_unix_epoch.rs
Normal file
78
src/time/ms_since_unix_epoch.rs
Normal file
@ -0,0 +1,78 @@
|
||||
//! De-/serialization functions for `std::time::SystemTime` objects represented as milliseconds
|
||||
//! since the UNIX epoch. Delegates to `js_int::UInt` to ensure integer size is within bounds.
|
||||
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use js_int::UInt;
|
||||
use serde::{
|
||||
de::{Deserialize, Deserializer},
|
||||
ser::{Error, Serialize, Serializer},
|
||||
};
|
||||
|
||||
/// Serialize a SystemTime.
|
||||
///
|
||||
/// Will fail if integer is greater than the maximum integer that can be unambiguously represented
|
||||
/// by an f64.
|
||||
pub fn serialize<S>(time: &SystemTime, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
// If this unwrap fails, the system this is executed is completely broken.
|
||||
let time_since_epoch = time.duration_since(UNIX_EPOCH).unwrap();
|
||||
match UInt::try_from(time_since_epoch.as_millis()) {
|
||||
Ok(uint) => uint.serialize(serializer),
|
||||
Err(err) => Err(S::Error::custom(err)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes a SystemTime.
|
||||
///
|
||||
/// Will fail if integer is greater than the maximum integer that can be unambiguously represented
|
||||
/// by an f64.
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<SystemTime, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let millis = UInt::deserialize(deserializer)?;
|
||||
Ok(UNIX_EPOCH + Duration::from_millis(millis.into()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
struct SystemTimeTest {
|
||||
#[serde(with = "super")]
|
||||
timestamp: SystemTime,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize() {
|
||||
let json = json!({ "timestamp": 3000 });
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_value::<SystemTimeTest>(json).unwrap(),
|
||||
SystemTimeTest {
|
||||
timestamp: UNIX_EPOCH + Duration::from_millis(3000),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize() {
|
||||
let request = SystemTimeTest {
|
||||
timestamp: UNIX_EPOCH + Duration::new(2, 0),
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::to_value(&request).unwrap(),
|
||||
json!({ "timestamp": 2000 })
|
||||
);
|
||||
}
|
||||
}
|
100
src/time/opt_ms_since_unix_epoch.rs
Normal file
100
src/time/opt_ms_since_unix_epoch.rs
Normal file
@ -0,0 +1,100 @@
|
||||
//! De-/serialization functions for `Option<std::time::SystemTime>` objects represented as
|
||||
//! milliseconds since the UNIX epoch. Delegates to `js_int::UInt` to ensure integer size is within
|
||||
//! bounds.
|
||||
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use js_int::UInt;
|
||||
use serde::{
|
||||
de::{Deserialize, Deserializer},
|
||||
ser::{Serialize, Serializer},
|
||||
};
|
||||
|
||||
/// Serialize an `Option<SystemTime>`.
|
||||
///
|
||||
/// Will fail if integer is greater than the maximum integer that can be unambiguously represented
|
||||
/// by an f64.
|
||||
pub fn serialize<S>(opt_time: &Option<SystemTime>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match opt_time {
|
||||
Some(time) => super::ms_since_unix_epoch::serialize(time, serializer),
|
||||
None => Option::<UInt>::serialize(&None, serializer),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserializes an `Option<SystemTime>`.
|
||||
///
|
||||
/// Will fail if integer is greater than the maximum integer that can be unambiguously represented
|
||||
/// by an f64.
|
||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<SystemTime>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(Option::<UInt>::deserialize(deserializer)?
|
||||
.map(|millis| UNIX_EPOCH + Duration::from_millis(millis.into())))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
struct SystemTimeTest {
|
||||
#[serde(with = "super", default, skip_serializing_if = "Option::is_none")]
|
||||
timestamp: Option<SystemTime>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_some() {
|
||||
let json = json!({ "timestamp": 3000 });
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_value::<SystemTimeTest>(json).unwrap(),
|
||||
SystemTimeTest {
|
||||
timestamp: Some(UNIX_EPOCH + Duration::from_millis(3000))
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_none_by_absence() {
|
||||
let json = json!({});
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_value::<SystemTimeTest>(json).unwrap(),
|
||||
SystemTimeTest { timestamp: None },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserialize_none_by_null() {
|
||||
let json = json!({ "timestamp": null });
|
||||
|
||||
assert_eq!(
|
||||
serde_json::from_value::<SystemTimeTest>(json).unwrap(),
|
||||
SystemTimeTest { timestamp: None },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_some() {
|
||||
let request = SystemTimeTest {
|
||||
timestamp: Some(UNIX_EPOCH + Duration::new(2, 0)),
|
||||
};
|
||||
assert_eq!(
|
||||
serde_json::to_value(&request).unwrap(),
|
||||
json!({ "timestamp": 2000 })
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_none() {
|
||||
let request = SystemTimeTest { timestamp: None };
|
||||
assert_eq!(serde_json::to_value(&request).unwrap(), json!({}));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user