Add serde::opt_ms_since_unix_epoch, use it in device::Device
This commit is contained in:
parent
207b77b53d
commit
6ddb9eca8b
@ -12,9 +12,10 @@ Breaking changes:
|
|||||||
* Remove deprecated `home_server` response field (removed in r0.4.0)
|
* Remove deprecated `home_server` response field (removed in r0.4.0)
|
||||||
* Update `r0::contact::get_contacts` endpoint to r0.6.0
|
* Update `r0::contact::get_contacts` endpoint to r0.6.0
|
||||||
* Change `UInt` timestamps to `SystemTime` in:
|
* Change `UInt` timestamps to `SystemTime` in:
|
||||||
* `media::get_media_preview`
|
* `media::get_media_preview::Request`
|
||||||
* `push::get_notifications`
|
* `push::get_notifications::Notification`
|
||||||
* `server::get_user_info`
|
* `server::get_user_info::ConnectionInfo`
|
||||||
|
* `device::Device`
|
||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Endpoints for managing devices.
|
//! Endpoints for managing devices.
|
||||||
|
|
||||||
use js_int::UInt;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use ruma_identifiers::DeviceId;
|
use ruma_identifiers::DeviceId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -20,5 +21,10 @@ pub struct Device {
|
|||||||
/// Most recently seen IP address of the session.
|
/// Most recently seen IP address of the session.
|
||||||
pub ip: Option<String>,
|
pub ip: Option<String>,
|
||||||
/// Unix timestamp that the session was last active.
|
/// Unix timestamp that the session was last active.
|
||||||
pub last_seen: Option<UInt>,
|
#[serde(
|
||||||
|
with = "crate::serde::time::opt_ms_since_unix_epoch",
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
pub last_seen: Option<SystemTime>,
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
//! De-/serialization functions for `std::time::SystemTime` objects
|
//! De-/serialization functions for `std::time::SystemTime` objects
|
||||||
|
|
||||||
pub mod ms_since_unix_epoch;
|
pub mod ms_since_unix_epoch;
|
||||||
|
pub mod opt_ms_since_unix_epoch;
|
||||||
|
100
src/serde/time/opt_ms_since_unix_epoch.rs
Normal file
100
src/serde/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