pub mod v3 {
use std::time::Duration;
use ruma_common::{
OwnedRoomId, OwnedUserId,
api::{auth_scheme::AccessToken, request, response},
metadata,
};
use serde::{Deserialize, Deserializer, Serialize, de::Error};
metadata! {
method: PUT,
authentication: AccessToken,
rate_limited: true,
history: {
1.0 => "/_matrix/client/r0/rooms/{room_id}/typing/{user_id}",
1.1 => "/_matrix/client/v3/rooms/{room_id}/typing/{user_id}",
}
}
#[request]
pub struct Request {
#[ruma_api(path)]
pub room_id: OwnedRoomId,
#[ruma_api(path)]
pub user_id: OwnedUserId,
#[ruma_api(body)]
pub state: Typing,
}
#[response]
#[derive(Default)]
pub struct Response {}
impl Request {
pub fn new(user_id: OwnedUserId, room_id: OwnedRoomId, state: Typing) -> Self {
Self { user_id, room_id, state }
}
}
impl Response {
pub fn new() -> Self {
Self {}
}
}
#[derive(Clone, Copy, Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum Typing {
No,
Yes(TypingInfo),
}
impl From<TypingInfo> for Typing {
fn from(value: TypingInfo) -> Self {
Self::Yes(value)
}
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
pub struct TypingInfo {
pub timeout: Duration,
}
impl TypingInfo {
pub fn new(timeout: Duration) -> Self {
Self { timeout }
}
}
#[derive(Deserialize, Serialize)]
struct TypingSerdeRepr {
typing: bool,
#[serde(
with = "ruma_common::serde::duration::opt_ms",
default,
skip_serializing_if = "Option::is_none"
)]
timeout: Option<Duration>,
}
impl Serialize for Typing {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let repr = match self {
Self::No => TypingSerdeRepr { typing: false, timeout: None },
Self::Yes(TypingInfo { timeout }) => {
TypingSerdeRepr { typing: true, timeout: Some(*timeout) }
}
};
repr.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Typing {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let repr = TypingSerdeRepr::deserialize(deserializer)?;
Ok(if repr.typing {
Typing::Yes(TypingInfo {
timeout: repr.timeout.ok_or_else(|| D::Error::missing_field("timeout"))?,
})
} else {
Typing::No
})
}
}
}