events: Add TagName::User variant and display_name method

This commit is contained in:
Kévin Commaille 2021-05-06 18:00:21 +02:00 committed by GitHub
parent 97c3b5cf47
commit 6501e3dc30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,9 +1,9 @@
//! Types for the *m.tag* event.
use std::collections::BTreeMap;
use std::{collections::BTreeMap, error::Error, fmt, str::FromStr};
use ruma_events_macros::BasicEventContent;
use ruma_serde::StringEnum;
use ruma_serde::deserialize_cow_str;
use serde::{Deserialize, Serialize};
use crate::BasicEvent;
@ -36,29 +36,134 @@ impl From<Tags> for TagEventContent {
}
}
/// A user-defined tag name.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct UserTagName {
name: String,
}
impl AsRef<str> for UserTagName {
fn as_ref(&self) -> &str {
&self.name
}
}
impl FromStr for UserTagName {
type Err = InvalidUserTagName;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.starts_with("u.") {
Ok(Self { name: s.into() })
} else {
Err(InvalidUserTagName)
}
}
}
/// An error returned when attempting to create a UserTagName with a string that would make it
/// invalid.
#[derive(Debug)]
pub struct InvalidUserTagName;
impl fmt::Display for InvalidUserTagName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "missing 'u.' prefix in UserTagName")
}
}
impl Error for InvalidUserTagName {}
/// The name of a tag.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, StringEnum)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum TagName {
/// `m.favourite`: The user's favourite rooms. These should be shown with higher precedence
/// than other rooms.
#[ruma_enum(rename = "m.favourite")]
Favorite,
/// `m.lowpriority`: These should be shown with lower precedence than others.
#[ruma_enum(rename = "m.lowpriority")]
LowPriority,
/// `m.server_notice`: Used to identify
/// [Server Notice Rooms](https://matrix.org/docs/spec/client_server/r0.6.1#module-server-notices).
#[ruma_enum(rename = "m.server_notice")]
ServerNotice,
/// `u.*`: User-defined tag
User(UserTagName),
/// A custom tag
#[doc(hidden)]
_Custom(String),
}
impl TagName {
/// Returns the display name of the tag.
///
/// That means the string after `m.` or `u.` for spec- and user-defined tag names, and the
/// string after the last dot for custom tags. If no dot is found, returns the whole string.
pub fn display_name(&self) -> &str {
match self {
Self::_Custom(s) => {
let start = s.rfind('.').map(|p| p + 1).unwrap_or(0);
&self.as_ref()[start..]
}
_ => &self.as_ref()[2..],
}
}
}
impl AsRef<str> for TagName {
fn as_ref(&self) -> &str {
match self {
Self::Favorite => "m.favourite",
Self::LowPriority => "m.lowpriority",
Self::ServerNotice => "m.server_notice",
Self::User(tag) => tag.as_ref(),
Self::_Custom(s) => s,
}
}
}
impl<T> From<T> for TagName
where
T: AsRef<str> + Into<String>,
{
fn from(s: T) -> TagName {
match s.as_ref() {
"m.favourite" => Self::Favorite,
"m.lowpriority" => Self::LowPriority,
"m.server_notice" => Self::ServerNotice,
s if s.starts_with("u.") => Self::User(UserTagName { name: s.into() }),
s => Self::_Custom(s.into()),
}
}
}
impl fmt::Display for TagName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_ref())
}
}
impl<'de> Deserialize<'de> for TagName {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let cow = deserialize_cow_str(deserializer)?;
Ok(cow.into())
}
}
impl Serialize for TagName {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_ref())
}
}
/// Information about a tag.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
@ -107,4 +212,14 @@ mod tests {
})
);
}
#[test]
fn display_name() {
assert_eq!(TagName::Favorite.display_name(), "favourite");
assert_eq!(TagName::LowPriority.display_name(), "lowpriority");
assert_eq!(TagName::ServerNotice.display_name(), "server_notice");
assert_eq!(TagName::from("u.Work").display_name(), "Work");
assert_eq!(TagName::from("rs.conduit.rules").display_name(), "rules");
assert_eq!(TagName::from("Play").display_name(), "Play");
}
}