identifiers: Create MatrixId type for MatrixToUri
This commit is contained in:
parent
52268b5dc2
commit
1c23cd25b5
@ -4,9 +4,9 @@ use std::fmt;
|
|||||||
|
|
||||||
use percent_encoding::{percent_encode, AsciiSet, CONTROLS};
|
use percent_encoding::{percent_encode, AsciiSet, CONTROLS};
|
||||||
|
|
||||||
use crate::{EventId, ServerName};
|
use crate::{EventId, RoomAliasId, RoomId, RoomOrAliasId, ServerName, UserId};
|
||||||
|
|
||||||
const BASE_URL: &str = "https://matrix.to/#/";
|
const MATRIX_TO_BASE_URL: &str = "https://matrix.to/#/";
|
||||||
// Controls + Space + reserved characters from RFC 3986. In practice only the
|
// Controls + Space + reserved characters from RFC 3986. In practice only the
|
||||||
// reserved characters will be encountered most likely, but better be safe.
|
// reserved characters will be encountered most likely, but better be safe.
|
||||||
// https://datatracker.ietf.org/doc/html/rfc3986/#page-13
|
// https://datatracker.ietf.org/doc/html/rfc3986/#page-13
|
||||||
@ -30,35 +30,112 @@ const TO_ENCODE: &AsciiSet = &CONTROLS
|
|||||||
.add(b';')
|
.add(b';')
|
||||||
.add(b'=');
|
.add(b'=');
|
||||||
|
|
||||||
/// A reference to a user, room or event.
|
/// All Matrix Identifiers that can be represented as a Matrix URI.
|
||||||
///
|
|
||||||
/// Turn it into a `matrix.to` URL through its `Display` implementation (i.e. by
|
|
||||||
/// interpolating it in a formatting macro or via `.to_string()`).
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct MatrixToUri<'a> {
|
#[non_exhaustive]
|
||||||
id: &'a str,
|
pub enum MatrixId {
|
||||||
event_id: Option<&'a EventId>,
|
/// A room ID.
|
||||||
via: Vec<&'a ServerName>,
|
Room(Box<RoomId>),
|
||||||
|
|
||||||
|
/// A room alias.
|
||||||
|
RoomAlias(Box<RoomAliasId>),
|
||||||
|
|
||||||
|
/// A user ID.
|
||||||
|
User(Box<UserId>),
|
||||||
|
|
||||||
|
/// An event ID.
|
||||||
|
Event(Box<RoomOrAliasId>, Box<EventId>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MatrixToUri<'a> {
|
impl MatrixId {
|
||||||
pub(crate) fn new(id: &'a str, via: Vec<&'a ServerName>) -> Self {
|
/// Construct a string with sigils from `self`.
|
||||||
Self { id, event_id: None, via }
|
///
|
||||||
}
|
/// The identifiers will start with a sigil and be percent encoded.
|
||||||
|
///
|
||||||
pub(crate) fn event(id: &'a str, event_id: &'a EventId, via: Vec<&'a ServerName>) -> Self {
|
/// For events, the room ID or alias and the event ID will be separated by
|
||||||
Self { id, event_id: Some(event_id), via }
|
/// a slash.
|
||||||
}
|
pub(crate) fn to_string_with_sigil(&self) -> String {
|
||||||
}
|
match self {
|
||||||
|
Self::Room(room_id) => percent_encode(room_id.as_bytes(), TO_ENCODE).to_string(),
|
||||||
impl<'a> fmt::Display for MatrixToUri<'a> {
|
Self::RoomAlias(room_alias) => {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
percent_encode(room_alias.as_bytes(), TO_ENCODE).to_string()
|
||||||
f.write_str(BASE_URL)?;
|
}
|
||||||
write!(f, "{}", percent_encode(self.id.as_bytes(), TO_ENCODE))?;
|
Self::User(user_id) => percent_encode(user_id.as_bytes(), TO_ENCODE).to_string(),
|
||||||
|
Self::Event(room_id, event_id) => format!(
|
||||||
if let Some(ev_id) = self.event_id {
|
"{}/{}",
|
||||||
write!(f, "/{}", percent_encode(ev_id.as_bytes(), TO_ENCODE))?;
|
percent_encode(room_id.as_bytes(), TO_ENCODE),
|
||||||
|
percent_encode(event_id.as_bytes(), TO_ENCODE),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&RoomId> for MatrixId {
|
||||||
|
fn from(room_id: &RoomId) -> Self {
|
||||||
|
Self::Room(room_id.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&RoomAliasId> for MatrixId {
|
||||||
|
fn from(room_alias: &RoomAliasId) -> Self {
|
||||||
|
Self::RoomAlias(room_alias.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&UserId> for MatrixId {
|
||||||
|
fn from(user_id: &UserId) -> Self {
|
||||||
|
Self::User(user_id.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(&RoomOrAliasId, &EventId)> for MatrixId {
|
||||||
|
fn from(ids: (&RoomOrAliasId, &EventId)) -> Self {
|
||||||
|
Self::Event(ids.0.into(), ids.1.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(&RoomId, &EventId)> for MatrixId {
|
||||||
|
fn from(ids: (&RoomId, &EventId)) -> Self {
|
||||||
|
Self::Event(<&RoomOrAliasId>::from(ids.0).into(), ids.1.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(&RoomAliasId, &EventId)> for MatrixId {
|
||||||
|
fn from(ids: (&RoomAliasId, &EventId)) -> Self {
|
||||||
|
Self::Event(<&RoomOrAliasId>::from(ids.0).into(), ids.1.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `matrix.to` URI representation of a user, room or event.
|
||||||
|
///
|
||||||
|
/// Get the URI through its `Display` implementation (i.e. by interpolating it
|
||||||
|
/// in a formatting macro or via `.to_string()`).
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct MatrixToUri {
|
||||||
|
id: MatrixId,
|
||||||
|
via: Vec<Box<ServerName>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatrixToUri {
|
||||||
|
pub(crate) fn new(id: MatrixId, via: Vec<&ServerName>) -> Self {
|
||||||
|
Self { id, via: via.into_iter().map(ToOwned::to_owned).collect() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The identifier represented by this `matrix.to` URI.
|
||||||
|
pub fn id(&self) -> &MatrixId {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Matrix servers usable to route a `RoomId`.
|
||||||
|
pub fn via(&self) -> &[Box<ServerName>] {
|
||||||
|
&self.via
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for MatrixToUri {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(MATRIX_TO_BASE_URL)?;
|
||||||
|
write!(f, "{}", self.id().to_string_with_sigil())?;
|
||||||
|
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for server_name in &self.via {
|
for server_name in &self.via {
|
||||||
@ -74,13 +151,35 @@ impl<'a> fmt::Display for MatrixToUri<'a> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::user_id;
|
use crate::{event_id, room_alias_id, room_id, server_name, user_id};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn matrix_to_uri() {
|
fn display_matrixtouri() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
user_id!("@jplatte:notareal.hs").matrix_to_url().to_string(),
|
user_id!("@jplatte:notareal.hs").matrix_to_url().to_string(),
|
||||||
"https://matrix.to/#/%40jplatte%3Anotareal.hs"
|
"https://matrix.to/#/%40jplatte%3Anotareal.hs"
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
room_alias_id!("#ruma:notareal.hs").matrix_to_url().to_string(),
|
||||||
|
"https://matrix.to/#/%23ruma%3Anotareal.hs"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
room_id!("!ruma:notareal.hs")
|
||||||
|
.matrix_to_url(vec![server_name!("notareal.hs")])
|
||||||
|
.to_string(),
|
||||||
|
"https://matrix.to/#/%21ruma%3Anotareal.hs?via=notareal.hs"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
room_alias_id!("#ruma:notareal.hs")
|
||||||
|
.matrix_to_event_url(event_id!("$event:notareal.hs"))
|
||||||
|
.to_string(),
|
||||||
|
"https://matrix.to/#/%23ruma%3Anotareal.hs/%24event%3Anotareal.hs"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
room_id!("!ruma:notareal.hs")
|
||||||
|
.matrix_to_event_url(event_id!("$event:notareal.hs"))
|
||||||
|
.to_string(),
|
||||||
|
"https://matrix.to/#/%21ruma%3Anotareal.hs/%24event%3Anotareal.hs"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,13 @@ impl RoomAliasId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `matrix.to` reference for this room alias ID.
|
/// Create a `matrix.to` reference for this room alias ID.
|
||||||
pub fn matrix_to_url(&self) -> MatrixToUri<'_> {
|
pub fn matrix_to_url(&self) -> MatrixToUri {
|
||||||
MatrixToUri::new(self.as_str(), Vec::new())
|
MatrixToUri::new(self.into(), Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `matrix.to` reference for an event scoped under this room alias ID.
|
/// Create a `matrix.to` reference for an event scoped under this room alias ID.
|
||||||
pub fn matrix_to_event_url<'a>(&'a self, ev_id: &'a EventId) -> MatrixToUri<'a> {
|
pub fn matrix_to_event_url(&self, ev_id: &EventId) -> MatrixToUri {
|
||||||
MatrixToUri::event(self.as_str(), ev_id, Vec::new())
|
MatrixToUri::new((self, ev_id).into(), Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn colon_idx(&self) -> usize {
|
fn colon_idx(&self) -> usize {
|
||||||
|
@ -52,16 +52,13 @@ impl RoomId {
|
|||||||
/// "https://matrix.to/#/%21somewhere%3Aexample.org?via=example.org&via=alt.example.org"
|
/// "https://matrix.to/#/%21somewhere%3Aexample.org?via=example.org&via=alt.example.org"
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
pub fn matrix_to_url<'a>(
|
pub fn matrix_to_url<'a>(&self, via: impl IntoIterator<Item = &'a ServerName>) -> MatrixToUri {
|
||||||
&'a self,
|
MatrixToUri::new(self.into(), via.into_iter().collect())
|
||||||
via: impl IntoIterator<Item = &'a ServerName>,
|
|
||||||
) -> MatrixToUri<'a> {
|
|
||||||
MatrixToUri::new(self.as_str(), via.into_iter().collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a `matrix.to` reference for an event scoped under this room ID.
|
/// Create a `matrix.to` reference for an event scoped under this room ID.
|
||||||
pub fn matrix_to_event_url<'a>(&'a self, ev_id: &'a EventId) -> MatrixToUri<'a> {
|
pub fn matrix_to_event_url(&self, ev_id: &EventId) -> MatrixToUri {
|
||||||
MatrixToUri::event(self.as_str(), ev_id, Vec::new())
|
MatrixToUri::new((self, ev_id).into(), Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn colon_idx(&self) -> usize {
|
fn colon_idx(&self) -> usize {
|
||||||
|
@ -116,8 +116,8 @@ impl UserId {
|
|||||||
/// display_name = "jplatte",
|
/// display_name = "jplatte",
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
pub fn matrix_to_url(&self) -> MatrixToUri<'_> {
|
pub fn matrix_to_url(&self) -> MatrixToUri {
|
||||||
MatrixToUri::new(self.as_str(), Vec::new())
|
MatrixToUri::new(self.into(), Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn colon_idx(&self) -> usize {
|
fn colon_idx(&self) -> usize {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user