ruma_client_api/typing/
create_typing_event.rs

1//! `PUT /_matrix/client/*/rooms/{roomId}/typing/{userId}`
2//!
3//! Send a typing event to a room.
4
5pub mod v3 {
6    //! `/v3/` ([spec])
7    //!
8    //! [spec]: https://spec.matrix.org/latest/client-server-api/#put_matrixclientv3roomsroomidtypinguserid
9
10    use std::time::Duration;
11
12    use ruma_common::{
13        OwnedRoomId, OwnedUserId,
14        api::{auth_scheme::AccessToken, request, response},
15        metadata,
16    };
17    use serde::{Deserialize, Deserializer, Serialize, de::Error};
18
19    metadata! {
20        method: PUT,
21        authentication: AccessToken,
22        rate_limited: true,
23        history: {
24            1.0 => "/_matrix/client/r0/rooms/{room_id}/typing/{user_id}",
25            1.1 => "/_matrix/client/v3/rooms/{room_id}/typing/{user_id}",
26        }
27    }
28
29    /// Request type for the `create_typing_event` endpoint.
30    #[request(error = crate::Error)]
31    pub struct Request {
32        /// The room in which the user is typing.
33        #[ruma_api(path)]
34        pub room_id: OwnedRoomId,
35
36        /// The user who has started to type.
37        #[ruma_api(path)]
38        pub user_id: OwnedUserId,
39
40        /// Whether the user is typing within a length of time or not.
41        #[ruma_api(body)]
42        pub state: Typing,
43    }
44
45    /// Response type for the `create_typing_event` endpoint.
46    #[response(error = crate::Error)]
47    #[derive(Default)]
48    pub struct Response {}
49
50    impl Request {
51        /// Creates a new `Request` with the given user ID, room ID and typing state.
52        pub fn new(user_id: OwnedUserId, room_id: OwnedRoomId, state: Typing) -> Self {
53            Self { user_id, room_id, state }
54        }
55    }
56
57    impl Response {
58        /// Creates an empty `Response`.
59        pub fn new() -> Self {
60            Self {}
61        }
62    }
63
64    /// A mark for whether the user is typing within a length of time or not.
65    #[derive(Clone, Copy, Debug, Serialize)]
66    #[serde(into = "TypingInner")]
67    #[allow(clippy::exhaustive_enums)]
68    pub enum Typing {
69        /// Not typing.
70        No,
71
72        /// Typing during the specified length of time.
73        Yes(Duration),
74    }
75
76    #[derive(Deserialize, Serialize)]
77    struct TypingInner {
78        typing: bool,
79
80        #[serde(
81            with = "ruma_common::serde::duration::opt_ms",
82            default,
83            skip_serializing_if = "Option::is_none"
84        )]
85        timeout: Option<Duration>,
86    }
87
88    impl From<Typing> for TypingInner {
89        fn from(typing: Typing) -> Self {
90            match typing {
91                Typing::No => Self { typing: false, timeout: None },
92                Typing::Yes(time) => Self { typing: true, timeout: Some(time) },
93            }
94        }
95    }
96
97    impl<'de> Deserialize<'de> for Typing {
98        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
99        where
100            D: Deserializer<'de>,
101        {
102            let inner = TypingInner::deserialize(deserializer)?;
103
104            match (inner.typing, inner.timeout) {
105                (false, _) => Ok(Self::No),
106                (true, Some(time)) => Ok(Self::Yes(time)),
107                _ => Err(D::Error::missing_field("timeout")),
108            }
109        }
110    }
111}