1//! Types for the `m.poll.end` event.
23use std::{
4 collections::{btree_map, BTreeMap},
5 ops::Deref,
6};
78use js_int::UInt;
9use ruma_common::OwnedEventId;
10use ruma_macros::EventContent;
11use serde::{Deserialize, Serialize};
1213use crate::{message::TextContentBlock, relation::Reference};
1415/// The payload for a poll end event.
16///
17/// This type can be generated from the poll start and poll response events with
18/// [`OriginalSyncPollStartEvent::compile_results()`].
19///
20/// This is the event content that should be sent for room versions that support extensible events.
21/// As of Matrix 1.7, none of the stable room versions (1 through 10) support extensible events.
22///
23/// To send a poll end event for a room version that does not support extensible events, use
24/// [`UnstablePollEndEventContent`].
25///
26/// [`OriginalSyncPollStartEvent::compile_results()`]: super::start::OriginalSyncPollStartEvent::compile_results
27/// [`UnstablePollEndEventContent`]: super::unstable_end::UnstablePollEndEventContent
28#[derive(Clone, Debug, Serialize, Deserialize, EventContent)]
29#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
30#[ruma_event(type = "m.poll.end", kind = MessageLike)]
31pub struct PollEndEventContent {
32/// The text representation of the results.
33#[serde(rename = "m.text")]
34pub text: TextContentBlock,
3536/// The sender's perspective of the results.
37#[serde(rename = "m.poll.results", skip_serializing_if = "Option::is_none")]
38pub poll_results: Option<PollResultsContentBlock>,
3940/// Whether this message is automated.
41#[cfg(feature = "unstable-msc3955")]
42 #[serde(
43 default,
44 skip_serializing_if = "ruma_common::serde::is_default",
45 rename = "org.matrix.msc1767.automated"
46)]
47pub automated: bool,
4849/// Information about the poll start event this responds to.
50#[serde(rename = "m.relates_to")]
51pub relates_to: Reference,
52}
5354impl PollEndEventContent {
55/// Creates a new `PollEndEventContent` with the given fallback representation and
56 /// that responds to the given poll start event ID.
57pub fn new(text: TextContentBlock, poll_start_id: OwnedEventId) -> Self {
58Self {
59 text,
60 poll_results: None,
61#[cfg(feature = "unstable-msc3955")]
62automated: false,
63 relates_to: Reference::new(poll_start_id),
64 }
65 }
6667/// Creates a new `PollEndEventContent` with the given plain text fallback representation and
68 /// that responds to the given poll start event ID.
69pub fn with_plain_text(plain_text: impl Into<String>, poll_start_id: OwnedEventId) -> Self {
70Self {
71 text: TextContentBlock::plain(plain_text),
72 poll_results: None,
73#[cfg(feature = "unstable-msc3955")]
74automated: false,
75 relates_to: Reference::new(poll_start_id),
76 }
77 }
78}
7980/// A block for the results of a poll.
81///
82/// This is a map of answer ID to number of votes.
83#[derive(Clone, Debug, Default, Serialize, Deserialize)]
84#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
85pub struct PollResultsContentBlock(BTreeMap<String, UInt>);
8687impl PollResultsContentBlock {
88/// Get these results sorted from the highest number of votes to the lowest.
89 ///
90 /// Returns a list of `(answer ID, number of votes)`.
91pub fn sorted(&self) -> Vec<(&str, UInt)> {
92let mut sorted = self.0.iter().map(|(id, count)| (id.as_str(), *count)).collect::<Vec<_>>();
93 sorted.sort_by(|(_, a), (_, b)| b.cmp(a));
94 sorted
95 }
96}
9798impl From<BTreeMap<String, UInt>> for PollResultsContentBlock {
99fn from(value: BTreeMap<String, UInt>) -> Self {
100Self(value)
101 }
102}
103104impl IntoIterator for PollResultsContentBlock {
105type Item = (String, UInt);
106type IntoIter = btree_map::IntoIter<String, UInt>;
107108fn into_iter(self) -> Self::IntoIter {
109self.0.into_iter()
110 }
111}
112113impl FromIterator<(String, UInt)> for PollResultsContentBlock {
114fn from_iter<T: IntoIterator<Item = (String, UInt)>>(iter: T) -> Self {
115Self(BTreeMap::from_iter(iter))
116 }
117}
118119impl Deref for PollResultsContentBlock {
120type Target = BTreeMap<String, UInt>;
121122fn deref(&self) -> &Self::Target {
123&self.0
124}
125}