Add borrowed id types
This commit is contained in:
parent
06c52c2abb
commit
622d69884c
@ -6,8 +6,8 @@ sources:
|
|||||||
tasks:
|
tasks:
|
||||||
- rustup: |
|
- rustup: |
|
||||||
# We specify --profile minimal because we'd otherwise download docs
|
# We specify --profile minimal because we'd otherwise download docs
|
||||||
rustup toolchain install 1.36.0 --profile minimal
|
rustup toolchain install 1.42.0 --profile minimal
|
||||||
rustup default 1.36.0
|
rustup default 1.42.0
|
||||||
- test: |
|
- test: |
|
||||||
cd ruma-identifiers
|
cd ruma-identifiers
|
||||||
|
|
||||||
|
@ -37,13 +37,13 @@ use crate::{error::Error, parse_id, validate_id};
|
|||||||
/// "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg"
|
/// "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg"
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct EventId {
|
pub struct EventId<T> {
|
||||||
full_id: Box<str>,
|
full_id: T,
|
||||||
colon_idx: Option<NonZeroU8>,
|
colon_idx: Option<NonZeroU8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventId {
|
impl<T> EventId<T> {
|
||||||
/// Attempts to generate an `EventId` for the given origin server with a localpart consisting
|
/// Attempts to generate an `EventId` for the given origin server with a localpart consisting
|
||||||
/// of 18 random ASCII characters. This should only be used for events in the original format
|
/// of 18 random ASCII characters. This should only be used for events in the original format
|
||||||
/// as used by Matrix room versions 1 and 2.
|
/// as used by Matrix room versions 1 and 2.
|
||||||
@ -52,7 +52,10 @@ impl EventId {
|
|||||||
/// parsed as a valid host.
|
/// parsed as a valid host.
|
||||||
#[cfg(feature = "rand")]
|
#[cfg(feature = "rand")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
||||||
pub fn new(server_name: &str) -> Result<Self, Error> {
|
pub fn new(server_name: &str) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
String: Into<T>,
|
||||||
|
{
|
||||||
use crate::{generate_localpart, is_valid_server_name};
|
use crate::{generate_localpart, is_valid_server_name};
|
||||||
|
|
||||||
if !is_valid_server_name(server_name) {
|
if !is_valid_server_name(server_name) {
|
||||||
@ -69,21 +72,27 @@ impl EventId {
|
|||||||
/// Returns the event's unique ID. For the original event format as used by Matrix room
|
/// Returns the event's unique ID. For the original event format as used by Matrix room
|
||||||
/// versions 1 and 2, this is the "localpart" that precedes the homeserver. For later formats,
|
/// versions 1 and 2, this is the "localpart" that precedes the homeserver. For later formats,
|
||||||
/// this is the entire ID without the leading $ sigil.
|
/// this is the entire ID without the leading $ sigil.
|
||||||
pub fn localpart(&self) -> &str {
|
pub fn localpart(&self) -> &str
|
||||||
|
where
|
||||||
|
T: AsRef<str>,
|
||||||
|
{
|
||||||
let idx = match self.colon_idx {
|
let idx = match self.colon_idx {
|
||||||
Some(idx) => idx.get() as usize,
|
Some(idx) => idx.get() as usize,
|
||||||
None => self.full_id.len(),
|
None => self.full_id.as_ref().len(),
|
||||||
};
|
};
|
||||||
|
|
||||||
&self.full_id[1..idx]
|
&self.full_id.as_ref()[1..idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the server name of the event ID.
|
/// Returns the server name of the event ID.
|
||||||
///
|
///
|
||||||
/// Only applicable to events in the original format as used by Matrix room versions 1 and 2.
|
/// Only applicable to events in the original format as used by Matrix room versions 1 and 2.
|
||||||
pub fn server_name(&self) -> Option<&str> {
|
pub fn server_name(&self) -> Option<&str>
|
||||||
|
where
|
||||||
|
T: AsRef<str>,
|
||||||
|
{
|
||||||
self.colon_idx
|
self.colon_idx
|
||||||
.map(|idx| &self.full_id[idx.get() as usize + 1..])
|
.map(|idx| &self.full_id.as_ref()[idx.get() as usize + 1..])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,9 +100,9 @@ impl EventId {
|
|||||||
///
|
///
|
||||||
/// If using the original event format as used by Matrix room versions 1 and 2, the string must
|
/// If using the original event format as used by Matrix room versions 1 and 2, the string must
|
||||||
/// include the leading $ sigil, the localpart, a literal colon, and a valid homeserver hostname.
|
/// include the leading $ sigil, the localpart, a literal colon, and a valid homeserver hostname.
|
||||||
fn try_from<S>(event_id: S) -> Result<EventId, Error>
|
fn try_from<S, T>(event_id: S) -> Result<EventId<T>, Error>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + Into<Box<str>>,
|
S: AsRef<str> + Into<T>,
|
||||||
{
|
{
|
||||||
if event_id.as_ref().contains(':') {
|
if event_id.as_ref().contains(':') {
|
||||||
let colon_idx = parse_id(event_id.as_ref(), &['$'])?;
|
let colon_idx = parse_id(event_id.as_ref(), &['$'])?;
|
||||||
@ -121,9 +130,10 @@ mod tests {
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde_json::{from_str, to_string};
|
use serde_json::{from_str, to_string};
|
||||||
|
|
||||||
use super::EventId;
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
|
type EventId = super::EventId<Box<str>>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_original_event_id() {
|
fn valid_original_event_id() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
51
src/lib.rs
51
src/lib.rs
@ -5,7 +5,7 @@
|
|||||||
#![deny(
|
#![deny(
|
||||||
missing_copy_implementations,
|
missing_copy_implementations,
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
missing_docs
|
//missing_docs
|
||||||
)]
|
)]
|
||||||
// Since we support Rust 1.36.0, we can't apply this suggestion yet
|
// Since we support Rust 1.36.0, we can't apply this suggestion yet
|
||||||
#![allow(clippy::use_self)]
|
#![allow(clippy::use_self)]
|
||||||
@ -17,25 +17,52 @@ use std::num::NonZeroU8;
|
|||||||
use serde::de::{self, Deserialize as _, Deserializer, Unexpected};
|
use serde::de::{self, Deserialize as _, Deserializer, Unexpected};
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::{
|
pub use crate::{error::Error, server_name::is_valid_server_name};
|
||||||
device_id::DeviceId, error::Error, event_id::EventId, room_alias_id::RoomAliasId,
|
|
||||||
room_id::RoomId, room_id_or_room_alias_id::RoomIdOrAliasId, room_version_id::RoomVersionId,
|
|
||||||
server_name::is_valid_server_name, user_id::UserId,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
pub mod device_id;
|
|
||||||
mod error;
|
mod error;
|
||||||
mod event_id;
|
|
||||||
mod room_alias_id;
|
|
||||||
mod room_id;
|
|
||||||
mod room_id_or_room_alias_id;
|
|
||||||
mod room_version_id;
|
|
||||||
mod server_name;
|
mod server_name;
|
||||||
|
|
||||||
|
pub mod device_id;
|
||||||
|
pub mod event_id;
|
||||||
|
pub mod room_alias_id;
|
||||||
|
pub mod room_id;
|
||||||
|
pub mod room_id_or_room_alias_id;
|
||||||
|
pub mod room_version_id;
|
||||||
pub mod user_id;
|
pub mod user_id;
|
||||||
|
|
||||||
|
/// An owned event ID.
|
||||||
|
pub type EventId = event_id::EventId<Box<str>>;
|
||||||
|
/// A reference to an event ID.
|
||||||
|
pub type EventIdRef<'a> = event_id::EventId<&'a str>;
|
||||||
|
|
||||||
|
/// An owned room alias ID.
|
||||||
|
pub type RoomAliasId = room_alias_id::RoomAliasId<Box<str>>;
|
||||||
|
/// A reference to a room alias ID.
|
||||||
|
pub type RoomAliasIdRef<'a> = room_alias_id::RoomAliasId<&'a str>;
|
||||||
|
|
||||||
|
/// An owned room ID.
|
||||||
|
pub type RoomId = room_id::RoomId<Box<str>>;
|
||||||
|
/// A reference to a room ID.
|
||||||
|
pub type RoomIdRef<'a> = room_id::RoomId<&'a str>;
|
||||||
|
|
||||||
|
/// An owned room alias ID or room ID.
|
||||||
|
pub type RoomIdOrAliasId = room_id_or_room_alias_id::RoomIdOrAliasId<Box<str>>;
|
||||||
|
/// A reference to a room alias ID or room ID.
|
||||||
|
pub type RoomIdOrAliasIdRef<'a> = room_id_or_room_alias_id::RoomIdOrAliasId<&'a str>;
|
||||||
|
|
||||||
|
/// An owned room version ID.
|
||||||
|
pub type RoomVersionId = room_version_id::RoomVersionId<Box<str>>;
|
||||||
|
/// A reference to a room version ID.
|
||||||
|
pub type RoomVersionIdRef<'a> = room_version_id::RoomVersionId<&'a str>;
|
||||||
|
|
||||||
|
/// An owned user ID.
|
||||||
|
pub type UserId = user_id::UserId<Box<str>>;
|
||||||
|
/// A reference to a user ID.
|
||||||
|
pub type UserIdRef<'a> = user_id::UserId<&'a str>;
|
||||||
|
|
||||||
/// All identifiers must be 255 bytes or less.
|
/// All identifiers must be 255 bytes or less.
|
||||||
const MAX_BYTES: usize = 255;
|
const MAX_BYTES: usize = 255;
|
||||||
/// The minimum number of characters an ID can be.
|
/// The minimum number of characters an ID can be.
|
||||||
|
@ -1,12 +1,20 @@
|
|||||||
macro_rules! common_impls {
|
macro_rules! common_impls {
|
||||||
($id:ident, $try_from:ident, $desc:literal) => {
|
($id:ident, $try_from:ident, $desc:literal) => {
|
||||||
impl ::std::convert::From<$id> for ::std::string::String {
|
impl ::std::convert::From<$id<Box<str>>> for ::std::string::String {
|
||||||
fn from(id: $id) -> Self {
|
fn from(id: $id<Box<str>>) -> Self {
|
||||||
id.full_id.into()
|
id.full_id.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::convert::TryFrom<&str> for $id {
|
impl<'a> ::std::convert::TryFrom<&'a str> for $id<&'a str> {
|
||||||
|
type Error = crate::error::Error;
|
||||||
|
|
||||||
|
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||||
|
$try_from(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::convert::TryFrom<&str> for $id<Box<str>> {
|
||||||
type Error = crate::error::Error;
|
type Error = crate::error::Error;
|
||||||
|
|
||||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||||
@ -14,7 +22,7 @@ macro_rules! common_impls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::convert::TryFrom<String> for $id {
|
impl ::std::convert::TryFrom<String> for $id<Box<str>> {
|
||||||
type Error = crate::error::Error;
|
type Error = crate::error::Error;
|
||||||
|
|
||||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||||
@ -22,56 +30,56 @@ macro_rules! common_impls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::convert::AsRef<str> for $id {
|
impl<T: ::std::convert::AsRef<str>> ::std::convert::AsRef<str> for $id<T> {
|
||||||
fn as_ref(&self) -> &str {
|
fn as_ref(&self) -> &str {
|
||||||
&self.full_id
|
self.full_id.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::fmt::Display for $id {
|
impl<T: ::std::fmt::Display> ::std::fmt::Display for $id<T> {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
write!(f, "{}", self.full_id)
|
write!(f, "{}", self.full_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::cmp::PartialEq for $id {
|
impl<T: ::std::cmp::PartialEq> ::std::cmp::PartialEq for $id<T> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.full_id == other.full_id
|
self.full_id == other.full_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::cmp::Eq for $id {}
|
impl<T: ::std::cmp::Eq> ::std::cmp::Eq for $id<T> {}
|
||||||
|
|
||||||
impl ::std::cmp::PartialOrd for $id {
|
impl<T: ::std::cmp::PartialOrd> ::std::cmp::PartialOrd for $id<T> {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
|
||||||
::std::cmp::PartialOrd::partial_cmp(&self.full_id, &other.full_id)
|
::std::cmp::PartialOrd::partial_cmp(&self.full_id, &other.full_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::cmp::Ord for $id {
|
impl<T: ::std::cmp::Ord> ::std::cmp::Ord for $id<T> {
|
||||||
fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
|
fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
|
||||||
::std::cmp::Ord::cmp(&self.full_id, &other.full_id)
|
::std::cmp::Ord::cmp(&self.full_id, &other.full_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::hash::Hash for $id {
|
impl<T: ::std::hash::Hash> ::std::hash::Hash for $id<T> {
|
||||||
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.full_id.hash(state);
|
self.full_id.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl ::serde::Serialize for $id {
|
impl<T: AsRef<str>> ::serde::Serialize for $id<T> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: ::serde::Serializer,
|
S: ::serde::Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_str(&self.full_id)
|
serializer.serialize_str(self.full_id.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl<'de> ::serde::Deserialize<'de> for $id {
|
impl<'de> ::serde::Deserialize<'de> for $id<Box<str>> {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: ::serde::Deserializer<'de>,
|
D: ::serde::Deserializer<'de>,
|
||||||
@ -80,27 +88,27 @@ macro_rules! common_impls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::cmp::PartialEq<&str> for $id {
|
impl<T: AsRef<str>> ::std::cmp::PartialEq<&str> for $id<T> {
|
||||||
fn eq(&self, other: &&str) -> bool {
|
fn eq(&self, other: &&str) -> bool {
|
||||||
&self.full_id[..] == *other
|
self.full_id.as_ref() == *other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::cmp::PartialEq<$id> for &str {
|
impl<T: AsRef<str>> ::std::cmp::PartialEq<$id<T>> for &str {
|
||||||
fn eq(&self, other: &$id) -> bool {
|
fn eq(&self, other: &$id<T>) -> bool {
|
||||||
*self == &other.full_id[..]
|
*self == other.full_id.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::cmp::PartialEq<::std::string::String> for $id {
|
impl<T: AsRef<str>> ::std::cmp::PartialEq<::std::string::String> for $id<T> {
|
||||||
fn eq(&self, other: &::std::string::String) -> bool {
|
fn eq(&self, other: &::std::string::String) -> bool {
|
||||||
&self.full_id[..] == &other[..]
|
self.full_id.as_ref() == &other[..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::cmp::PartialEq<$id> for ::std::string::String {
|
impl<T: AsRef<str>> ::std::cmp::PartialEq<$id<T>> for ::std::string::String {
|
||||||
fn eq(&self, other: &$id) -> bool {
|
fn eq(&self, other: &$id<T>) -> bool {
|
||||||
&self[..] == &other.full_id[..]
|
&self[..] == other.full_id.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -17,30 +17,30 @@ use crate::{error::Error, parse_id};
|
|||||||
/// "#ruma:example.com"
|
/// "#ruma:example.com"
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct RoomAliasId {
|
pub struct RoomAliasId<T> {
|
||||||
pub(crate) full_id: Box<str>,
|
pub(crate) full_id: T,
|
||||||
pub(crate) colon_idx: NonZeroU8,
|
pub(crate) colon_idx: NonZeroU8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomAliasId {
|
impl<T: AsRef<str>> RoomAliasId<T> {
|
||||||
/// Returns the room's alias.
|
/// Returns the room's alias.
|
||||||
pub fn alias(&self) -> &str {
|
pub fn alias(&self) -> &str {
|
||||||
&self.full_id[1..self.colon_idx.get() as usize]
|
&self.full_id.as_ref()[1..self.colon_idx.get() as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the server name of the room alias ID.
|
/// Returns the server name of the room alias ID.
|
||||||
pub fn server_name(&self) -> &str {
|
pub fn server_name(&self) -> &str {
|
||||||
&self.full_id[self.colon_idx.get() as usize + 1..]
|
&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to create a new Matrix room alias ID from a string representation.
|
/// Attempts to create a new Matrix room alias ID from a string representation.
|
||||||
///
|
///
|
||||||
/// The string must include the leading # sigil, the alias, a literal colon, and a server name.
|
/// The string must include the leading # sigil, the alias, a literal colon, and a server name.
|
||||||
fn try_from<S>(room_id: S) -> Result<RoomAliasId, Error>
|
fn try_from<S, T>(room_id: S) -> Result<RoomAliasId<T>, Error>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + Into<Box<str>>,
|
S: AsRef<str> + Into<T>,
|
||||||
{
|
{
|
||||||
let colon_idx = parse_id(room_id.as_ref(), &['#'])?;
|
let colon_idx = parse_id(room_id.as_ref(), &['#'])?;
|
||||||
|
|
||||||
@ -59,9 +59,10 @@ mod tests {
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde_json::{from_str, to_string};
|
use serde_json::{from_str, to_string};
|
||||||
|
|
||||||
use super::RoomAliasId;
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
|
type RoomAliasId = super::RoomAliasId<Box<str>>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_room_alias_id() {
|
fn valid_room_alias_id() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -17,20 +17,23 @@ use crate::{error::Error, parse_id};
|
|||||||
/// "!n8f893n9:example.com"
|
/// "!n8f893n9:example.com"
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct RoomId {
|
pub struct RoomId<T> {
|
||||||
pub(crate) full_id: Box<str>,
|
pub(crate) full_id: T,
|
||||||
pub(crate) colon_idx: NonZeroU8,
|
pub(crate) colon_idx: NonZeroU8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomId {
|
impl<T> RoomId<T> {
|
||||||
/// Attempts to generate a `RoomId` for the given origin server with a localpart consisting of
|
/// Attempts to generate a `RoomId` for the given origin server with a localpart consisting of
|
||||||
/// 18 random ASCII characters.
|
/// 18 random ASCII characters.
|
||||||
///
|
///
|
||||||
/// Fails if the given homeserver cannot be parsed as a valid host.
|
/// Fails if the given homeserver cannot be parsed as a valid host.
|
||||||
#[cfg(feature = "rand")]
|
#[cfg(feature = "rand")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
||||||
pub fn new(server_name: &str) -> Result<Self, Error> {
|
pub fn new(server_name: &str) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
String: Into<T>,
|
||||||
|
{
|
||||||
use crate::{generate_localpart, is_valid_server_name};
|
use crate::{generate_localpart, is_valid_server_name};
|
||||||
|
|
||||||
if !is_valid_server_name(server_name) {
|
if !is_valid_server_name(server_name) {
|
||||||
@ -45,22 +48,28 @@ impl RoomId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the rooms's unique ID.
|
/// Returns the rooms's unique ID.
|
||||||
pub fn localpart(&self) -> &str {
|
pub fn localpart(&self) -> &str
|
||||||
&self.full_id[1..self.colon_idx.get() as usize]
|
where
|
||||||
|
T: AsRef<str>,
|
||||||
|
{
|
||||||
|
&self.full_id.as_ref()[1..self.colon_idx.get() as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the server name of the room ID.
|
/// Returns the server name of the room ID.
|
||||||
pub fn server_name(&self) -> &str {
|
pub fn server_name(&self) -> &str
|
||||||
&self.full_id[self.colon_idx.get() as usize + 1..]
|
where
|
||||||
|
T: AsRef<str>,
|
||||||
|
{
|
||||||
|
&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to create a new Matrix room ID from a string representation.
|
/// Attempts to create a new Matrix room ID from a string representation.
|
||||||
///
|
///
|
||||||
/// The string must include the leading ! sigil, the localpart, a literal colon, and a server name.
|
/// The string must include the leading ! sigil, the localpart, a literal colon, and a server name.
|
||||||
fn try_from<S>(room_id: S) -> Result<RoomId, Error>
|
fn try_from<S, T>(room_id: S) -> Result<RoomId<T>, Error>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + Into<Box<str>>,
|
S: AsRef<str> + Into<T>,
|
||||||
{
|
{
|
||||||
let colon_idx = parse_id(room_id.as_ref(), &['!'])?;
|
let colon_idx = parse_id(room_id.as_ref(), &['!'])?;
|
||||||
|
|
||||||
@ -79,9 +88,10 @@ mod tests {
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde_json::{from_str, to_string};
|
use serde_json::{from_str, to_string};
|
||||||
|
|
||||||
use super::RoomId;
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
|
type RoomId = super::RoomId<Box<str>>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_room_id() {
|
fn valid_room_id() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use std::{convert::TryFrom, hint::unreachable_unchecked, num::NonZeroU8};
|
use std::{convert::TryFrom, hint::unreachable_unchecked, num::NonZeroU8};
|
||||||
|
|
||||||
use crate::{error::Error, parse_id, RoomAliasId, RoomId};
|
use crate::{error::Error, parse_id, room_alias_id::RoomAliasId, room_id::RoomId};
|
||||||
|
|
||||||
/// A Matrix room ID or a Matrix room alias ID.
|
/// A Matrix room ID or a Matrix room alias ID.
|
||||||
///
|
///
|
||||||
@ -23,21 +23,21 @@ use crate::{error::Error, parse_id, RoomAliasId, RoomId};
|
|||||||
/// "!n8f893n9:example.com"
|
/// "!n8f893n9:example.com"
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct RoomIdOrAliasId {
|
pub struct RoomIdOrAliasId<T> {
|
||||||
full_id: Box<str>,
|
full_id: T,
|
||||||
colon_idx: NonZeroU8,
|
colon_idx: NonZeroU8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomIdOrAliasId {
|
impl<T: AsRef<str>> RoomIdOrAliasId<T> {
|
||||||
/// Returns the local part (everything after the `!` or `#` and before the first colon).
|
/// Returns the local part (everything after the `!` or `#` and before the first colon).
|
||||||
pub fn localpart(&self) -> &str {
|
pub fn localpart(&self) -> &str {
|
||||||
&self.full_id[1..self.colon_idx.get() as usize]
|
&self.full_id.as_ref()[1..self.colon_idx.get() as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the server name of the room (alias) ID.
|
/// Returns the server name of the room (alias) ID.
|
||||||
pub fn server_name(&self) -> &str {
|
pub fn server_name(&self) -> &str {
|
||||||
&self.full_id[self.colon_idx.get() as usize + 1..]
|
&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this is a room id (starts with `'!'`)
|
/// Whether this is a room id (starts with `'!'`)
|
||||||
@ -53,7 +53,7 @@ impl RoomIdOrAliasId {
|
|||||||
/// Turn this `RoomIdOrAliasId` into `Either<RoomId, RoomAliasId>`
|
/// Turn this `RoomIdOrAliasId` into `Either<RoomId, RoomAliasId>`
|
||||||
#[cfg(feature = "either")]
|
#[cfg(feature = "either")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "either")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "either")))]
|
||||||
pub fn into_either(self) -> either::Either<RoomId, RoomAliasId> {
|
pub fn into_either(self) -> either::Either<RoomId<T>, RoomAliasId<T>> {
|
||||||
match self.variant() {
|
match self.variant() {
|
||||||
Variant::RoomId => either::Either::Left(RoomId {
|
Variant::RoomId => either::Either::Left(RoomId {
|
||||||
full_id: self.full_id,
|
full_id: self.full_id,
|
||||||
@ -67,7 +67,7 @@ impl RoomIdOrAliasId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn variant(&self) -> Variant {
|
fn variant(&self) -> Variant {
|
||||||
match self.full_id.bytes().next() {
|
match self.full_id.as_ref().bytes().next() {
|
||||||
Some(b'!') => Variant::RoomId,
|
Some(b'!') => Variant::RoomId,
|
||||||
Some(b'#') => Variant::RoomAliasId,
|
Some(b'#') => Variant::RoomAliasId,
|
||||||
_ => unsafe { unreachable_unchecked() },
|
_ => unsafe { unreachable_unchecked() },
|
||||||
@ -86,9 +86,9 @@ enum Variant {
|
|||||||
/// The string must either include the leading ! sigil, the localpart, a literal colon, and a
|
/// The string must either include the leading ! sigil, the localpart, a literal colon, and a
|
||||||
/// valid homeserver host or include the leading # sigil, the alias, a literal colon, and a
|
/// valid homeserver host or include the leading # sigil, the alias, a literal colon, and a
|
||||||
/// valid homeserver host.
|
/// valid homeserver host.
|
||||||
fn try_from<S>(room_id_or_alias_id: S) -> Result<RoomIdOrAliasId, Error>
|
fn try_from<S, T>(room_id_or_alias_id: S) -> Result<RoomIdOrAliasId<T>, Error>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + Into<Box<str>>,
|
S: AsRef<str> + Into<T>,
|
||||||
{
|
{
|
||||||
let colon_idx = parse_id(room_id_or_alias_id.as_ref(), &['#', '!'])?;
|
let colon_idx = parse_id(room_id_or_alias_id.as_ref(), &['#', '!'])?;
|
||||||
Ok(RoomIdOrAliasId {
|
Ok(RoomIdOrAliasId {
|
||||||
@ -103,22 +103,22 @@ common_impls!(
|
|||||||
"a Matrix room ID or room alias ID"
|
"a Matrix room ID or room alias ID"
|
||||||
);
|
);
|
||||||
|
|
||||||
impl From<RoomId> for RoomIdOrAliasId {
|
impl<T> From<RoomId<T>> for RoomIdOrAliasId<T> {
|
||||||
fn from(RoomId { full_id, colon_idx }: RoomId) -> Self {
|
fn from(RoomId { full_id, colon_idx }: RoomId<T>) -> Self {
|
||||||
Self { full_id, colon_idx }
|
Self { full_id, colon_idx }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RoomAliasId> for RoomIdOrAliasId {
|
impl<T> From<RoomAliasId<T>> for RoomIdOrAliasId<T> {
|
||||||
fn from(RoomAliasId { full_id, colon_idx }: RoomAliasId) -> Self {
|
fn from(RoomAliasId { full_id, colon_idx }: RoomAliasId<T>) -> Self {
|
||||||
Self { full_id, colon_idx }
|
Self { full_id, colon_idx }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<RoomIdOrAliasId> for RoomId {
|
impl<T: AsRef<str>> TryFrom<RoomIdOrAliasId<T>> for RoomId<T> {
|
||||||
type Error = RoomAliasId;
|
type Error = RoomAliasId<T>;
|
||||||
|
|
||||||
fn try_from(id: RoomIdOrAliasId) -> Result<RoomId, RoomAliasId> {
|
fn try_from(id: RoomIdOrAliasId<T>) -> Result<RoomId<T>, RoomAliasId<T>> {
|
||||||
match id.variant() {
|
match id.variant() {
|
||||||
Variant::RoomId => Ok(RoomId {
|
Variant::RoomId => Ok(RoomId {
|
||||||
full_id: id.full_id,
|
full_id: id.full_id,
|
||||||
@ -132,10 +132,10 @@ impl TryFrom<RoomIdOrAliasId> for RoomId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<RoomIdOrAliasId> for RoomAliasId {
|
impl<T: AsRef<str>> TryFrom<RoomIdOrAliasId<T>> for RoomAliasId<T> {
|
||||||
type Error = RoomId;
|
type Error = RoomId<T>;
|
||||||
|
|
||||||
fn try_from(id: RoomIdOrAliasId) -> Result<RoomAliasId, RoomId> {
|
fn try_from(id: RoomIdOrAliasId<T>) -> Result<RoomAliasId<T>, RoomId<T>> {
|
||||||
match id.variant() {
|
match id.variant() {
|
||||||
Variant::RoomAliasId => Ok(RoomAliasId {
|
Variant::RoomAliasId => Ok(RoomAliasId {
|
||||||
full_id: id.full_id,
|
full_id: id.full_id,
|
||||||
@ -156,9 +156,10 @@ mod tests {
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde_json::{from_str, to_string};
|
use serde_json::{from_str, to_string};
|
||||||
|
|
||||||
use super::RoomIdOrAliasId;
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
|
type RoomIdOrAliasId = super::RoomIdOrAliasId<Box<str>>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_room_id_or_alias_id_with_a_room_alias_id() {
|
fn valid_room_id_or_alias_id_with_a_room_alias_id() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -24,13 +24,13 @@ const MAX_CODE_POINTS: usize = 32;
|
|||||||
/// # use ruma_identifiers::RoomVersionId;
|
/// # use ruma_identifiers::RoomVersionId;
|
||||||
/// assert_eq!(RoomVersionId::try_from("1").unwrap().as_ref(), "1");
|
/// assert_eq!(RoomVersionId::try_from("1").unwrap().as_ref(), "1");
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct RoomVersionId(InnerRoomVersionId);
|
pub struct RoomVersionId<T>(InnerRoomVersionId<T>);
|
||||||
|
|
||||||
/// Possibile values for room version, distinguishing between official Matrix versions and custom
|
/// Possibile values for room version, distinguishing between official Matrix versions and custom
|
||||||
/// versions.
|
/// versions.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
enum InnerRoomVersionId {
|
enum InnerRoomVersionId<T> {
|
||||||
/// A version 1 room.
|
/// A version 1 room.
|
||||||
Version1,
|
Version1,
|
||||||
|
|
||||||
@ -50,10 +50,10 @@ enum InnerRoomVersionId {
|
|||||||
Version6,
|
Version6,
|
||||||
|
|
||||||
/// A custom room version.
|
/// A custom room version.
|
||||||
Custom(Box<str>),
|
Custom(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomVersionId {
|
impl<T> RoomVersionId<T> {
|
||||||
/// Creates a version 1 room ID.
|
/// Creates a version 1 room ID.
|
||||||
pub fn version_1() -> Self {
|
pub fn version_1() -> Self {
|
||||||
Self(InnerRoomVersionId::Version1)
|
Self(InnerRoomVersionId::Version1)
|
||||||
@ -85,7 +85,10 @@ impl RoomVersionId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a custom room version ID from the given string slice.
|
/// Creates a custom room version ID from the given string slice.
|
||||||
pub fn custom(id: String) -> Self {
|
pub fn custom(id: String) -> Self
|
||||||
|
where
|
||||||
|
String: Into<T>,
|
||||||
|
{
|
||||||
Self(InnerRoomVersionId::Custom(id.into()))
|
Self(InnerRoomVersionId::Custom(id.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,37 +107,37 @@ impl RoomVersionId {
|
|||||||
|
|
||||||
/// Whether or not this is a version 1 room.
|
/// Whether or not this is a version 1 room.
|
||||||
pub fn is_version_1(&self) -> bool {
|
pub fn is_version_1(&self) -> bool {
|
||||||
self.0 == InnerRoomVersionId::Version1
|
matches!(self.0, InnerRoomVersionId::Version1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether or not this is a version 2 room.
|
/// Whether or not this is a version 2 room.
|
||||||
pub fn is_version_2(&self) -> bool {
|
pub fn is_version_2(&self) -> bool {
|
||||||
self.0 == InnerRoomVersionId::Version2
|
matches!(self.0, InnerRoomVersionId::Version2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether or not this is a version 3 room.
|
/// Whether or not this is a version 3 room.
|
||||||
pub fn is_version_3(&self) -> bool {
|
pub fn is_version_3(&self) -> bool {
|
||||||
self.0 == InnerRoomVersionId::Version3
|
matches!(self.0, InnerRoomVersionId::Version3)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether or not this is a version 4 room.
|
/// Whether or not this is a version 4 room.
|
||||||
pub fn is_version_4(&self) -> bool {
|
pub fn is_version_4(&self) -> bool {
|
||||||
self.0 == InnerRoomVersionId::Version4
|
matches!(self.0, InnerRoomVersionId::Version4)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether or not this is a version 5 room.
|
/// Whether or not this is a version 5 room.
|
||||||
pub fn is_version_5(&self) -> bool {
|
pub fn is_version_5(&self) -> bool {
|
||||||
self.0 == InnerRoomVersionId::Version5
|
matches!(self.0, InnerRoomVersionId::Version5)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether or not this is a version 6 room.
|
/// Whether or not this is a version 6 room.
|
||||||
pub fn is_version_6(&self) -> bool {
|
pub fn is_version_6(&self) -> bool {
|
||||||
self.0 == InnerRoomVersionId::Version5
|
matches!(self.0, InnerRoomVersionId::Version5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RoomVersionId> for String {
|
impl From<RoomVersionId<Box<str>>> for String {
|
||||||
fn from(id: RoomVersionId) -> Self {
|
fn from(id: RoomVersionId<Box<str>>) -> Self {
|
||||||
match id.0 {
|
match id.0 {
|
||||||
InnerRoomVersionId::Version1 => "1".to_owned(),
|
InnerRoomVersionId::Version1 => "1".to_owned(),
|
||||||
InnerRoomVersionId::Version2 => "2".to_owned(),
|
InnerRoomVersionId::Version2 => "2".to_owned(),
|
||||||
@ -147,7 +150,7 @@ impl From<RoomVersionId> for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<str> for RoomVersionId {
|
impl<T: AsRef<str>> AsRef<str> for RoomVersionId<T> {
|
||||||
fn as_ref(&self) -> &str {
|
fn as_ref(&self) -> &str {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
InnerRoomVersionId::Version1 => "1",
|
InnerRoomVersionId::Version1 => "1",
|
||||||
@ -156,31 +159,31 @@ impl AsRef<str> for RoomVersionId {
|
|||||||
InnerRoomVersionId::Version4 => "4",
|
InnerRoomVersionId::Version4 => "4",
|
||||||
InnerRoomVersionId::Version5 => "5",
|
InnerRoomVersionId::Version5 => "5",
|
||||||
InnerRoomVersionId::Version6 => "6",
|
InnerRoomVersionId::Version6 => "6",
|
||||||
InnerRoomVersionId::Custom(version) => version,
|
InnerRoomVersionId::Custom(version) => version.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for RoomVersionId {
|
impl<T: AsRef<str>> Display for RoomVersionId<T> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.as_ref())
|
write!(f, "{}", self.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for RoomVersionId {
|
impl<T: PartialEq + AsRef<str>> PartialOrd for RoomVersionId<T> {
|
||||||
fn partial_cmp(&self, other: &RoomVersionId) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &RoomVersionId<T>) -> Option<Ordering> {
|
||||||
self.as_ref().partial_cmp(other.as_ref())
|
self.as_ref().partial_cmp(other.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for RoomVersionId {
|
impl<T: Eq + AsRef<str>> Ord for RoomVersionId<T> {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.as_ref().cmp(other.as_ref())
|
self.as_ref().cmp(other.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl Serialize for RoomVersionId {
|
impl<T: AsRef<str>> Serialize for RoomVersionId<T> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
@ -190,7 +193,7 @@ impl Serialize for RoomVersionId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl<'de> Deserialize<'de> for RoomVersionId {
|
impl<'de> Deserialize<'de> for RoomVersionId<Box<str>> {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
@ -200,9 +203,9 @@ impl<'de> Deserialize<'de> for RoomVersionId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to create a new Matrix room version ID from a string representation.
|
/// Attempts to create a new Matrix room version ID from a string representation.
|
||||||
fn try_from<S>(room_version_id: S) -> Result<RoomVersionId, Error>
|
fn try_from<S, T>(room_version_id: S) -> Result<RoomVersionId<T>, Error>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + Into<Box<str>>,
|
S: AsRef<str> + Into<T>,
|
||||||
{
|
{
|
||||||
let version = match room_version_id.as_ref() {
|
let version = match room_version_id.as_ref() {
|
||||||
"1" => RoomVersionId(InnerRoomVersionId::Version1),
|
"1" => RoomVersionId(InnerRoomVersionId::Version1),
|
||||||
@ -224,7 +227,15 @@ where
|
|||||||
Ok(version)
|
Ok(version)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for RoomVersionId {
|
impl<'a> TryFrom<&'a str> for RoomVersionId<&'a str> {
|
||||||
|
type Error = crate::error::Error;
|
||||||
|
|
||||||
|
fn try_from(s: &'a str) -> Result<Self, Error> {
|
||||||
|
try_from(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for RoomVersionId<Box<str>> {
|
||||||
type Error = crate::error::Error;
|
type Error = crate::error::Error;
|
||||||
|
|
||||||
fn try_from(s: &str) -> Result<Self, Error> {
|
fn try_from(s: &str) -> Result<Self, Error> {
|
||||||
@ -232,7 +243,7 @@ impl TryFrom<&str> for RoomVersionId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<String> for RoomVersionId {
|
impl TryFrom<String> for RoomVersionId<Box<str>> {
|
||||||
type Error = crate::error::Error;
|
type Error = crate::error::Error;
|
||||||
|
|
||||||
fn try_from(s: String) -> Result<Self, Error> {
|
fn try_from(s: String) -> Result<Self, Error> {
|
||||||
@ -240,26 +251,26 @@ impl TryFrom<String> for RoomVersionId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<&str> for RoomVersionId {
|
impl<T: AsRef<str>> PartialEq<&str> for RoomVersionId<T> {
|
||||||
fn eq(&self, other: &&str) -> bool {
|
fn eq(&self, other: &&str) -> bool {
|
||||||
self.as_ref() == *other
|
self.as_ref() == *other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<RoomVersionId> for &str {
|
impl<T: AsRef<str>> PartialEq<RoomVersionId<T>> for &str {
|
||||||
fn eq(&self, other: &RoomVersionId) -> bool {
|
fn eq(&self, other: &RoomVersionId<T>) -> bool {
|
||||||
*self == other.as_ref()
|
*self == other.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<String> for RoomVersionId {
|
impl<T: AsRef<str>> PartialEq<String> for RoomVersionId<T> {
|
||||||
fn eq(&self, other: &String) -> bool {
|
fn eq(&self, other: &String) -> bool {
|
||||||
self.as_ref() == other
|
self.as_ref() == other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<RoomVersionId> for String {
|
impl<T: AsRef<str>> PartialEq<RoomVersionId<T>> for String {
|
||||||
fn eq(&self, other: &RoomVersionId) -> bool {
|
fn eq(&self, other: &RoomVersionId<T>) -> bool {
|
||||||
self == other.as_ref()
|
self == other.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -271,9 +282,10 @@ mod tests {
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde_json::{from_str, to_string};
|
use serde_json::{from_str, to_string};
|
||||||
|
|
||||||
use super::RoomVersionId;
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
|
type RoomVersionId = super::RoomVersionId<Box<str>>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_version_1_room_version_id() {
|
fn valid_version_1_room_version_id() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -17,9 +17,9 @@ use crate::{error::Error, is_valid_server_name, parse_id};
|
|||||||
/// "@carl:example.com"
|
/// "@carl:example.com"
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct UserId {
|
pub struct UserId<T> {
|
||||||
full_id: Box<str>,
|
full_id: T,
|
||||||
colon_idx: NonZeroU8,
|
colon_idx: NonZeroU8,
|
||||||
/// Whether this user id is a historical one.
|
/// Whether this user id is a historical one.
|
||||||
///
|
///
|
||||||
@ -29,14 +29,17 @@ pub struct UserId {
|
|||||||
is_historical: bool,
|
is_historical: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserId {
|
impl<T> UserId<T> {
|
||||||
/// Attempts to generate a `UserId` for the given origin server with a localpart consisting of
|
/// Attempts to generate a `UserId` for the given origin server with a localpart consisting of
|
||||||
/// 12 random ASCII characters.
|
/// 12 random ASCII characters.
|
||||||
///
|
///
|
||||||
/// Fails if the given homeserver cannot be parsed as a valid host.
|
/// Fails if the given homeserver cannot be parsed as a valid host.
|
||||||
#[cfg(feature = "rand")]
|
#[cfg(feature = "rand")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
|
||||||
pub fn new(server_name: &str) -> Result<Self, Error> {
|
pub fn new(server_name: &str) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
String: Into<T>,
|
||||||
|
{
|
||||||
use crate::generate_localpart;
|
use crate::generate_localpart;
|
||||||
|
|
||||||
if !is_valid_server_name(server_name) {
|
if !is_valid_server_name(server_name) {
|
||||||
@ -59,13 +62,16 @@ impl UserId {
|
|||||||
/// localpart, not the localpart plus the `@` prefix, or the localpart plus server name without
|
/// localpart, not the localpart plus the `@` prefix, or the localpart plus server name without
|
||||||
/// the `@` prefix.
|
/// the `@` prefix.
|
||||||
pub fn parse_with_server_name(
|
pub fn parse_with_server_name(
|
||||||
id: impl AsRef<str> + Into<Box<str>>,
|
id: impl AsRef<str> + Into<T>,
|
||||||
server_name: &str,
|
server_name: &str,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error>
|
||||||
|
where
|
||||||
|
String: Into<T>,
|
||||||
|
{
|
||||||
let id_str = id.as_ref();
|
let id_str = id.as_ref();
|
||||||
|
|
||||||
if id_str.starts_with('@') {
|
if id_str.starts_with('@') {
|
||||||
try_from(id.into())
|
try_from(id)
|
||||||
} else {
|
} else {
|
||||||
let is_fully_conforming = localpart_is_fully_comforming(id_str)?;
|
let is_fully_conforming = localpart_is_fully_comforming(id_str)?;
|
||||||
if !is_valid_server_name(server_name) {
|
if !is_valid_server_name(server_name) {
|
||||||
@ -81,13 +87,19 @@ impl UserId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the user's localpart.
|
/// Returns the user's localpart.
|
||||||
pub fn localpart(&self) -> &str {
|
pub fn localpart(&self) -> &str
|
||||||
&self.full_id[1..self.colon_idx.get() as usize]
|
where
|
||||||
|
T: AsRef<str>,
|
||||||
|
{
|
||||||
|
&self.full_id.as_ref()[1..self.colon_idx.get() as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the server name of the user ID.
|
/// Returns the server name of the user ID.
|
||||||
pub fn server_name(&self) -> &str {
|
pub fn server_name(&self) -> &str
|
||||||
&self.full_id[self.colon_idx.get() as usize + 1..]
|
where
|
||||||
|
T: AsRef<str>,
|
||||||
|
{
|
||||||
|
&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this user ID is a historical one, i.e. one that doesn't conform to the latest
|
/// Whether this user ID is a historical one, i.e. one that doesn't conform to the latest
|
||||||
@ -101,9 +113,9 @@ impl UserId {
|
|||||||
/// Attempts to create a new Matrix user ID from a string representation.
|
/// Attempts to create a new Matrix user ID from a string representation.
|
||||||
///
|
///
|
||||||
/// The string must include the leading @ sigil, the localpart, a literal colon, and a server name.
|
/// The string must include the leading @ sigil, the localpart, a literal colon, and a server name.
|
||||||
fn try_from<S>(user_id: S) -> Result<UserId, Error>
|
fn try_from<S, T>(user_id: S) -> Result<UserId<T>, Error>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + Into<Box<str>>,
|
S: AsRef<str> + Into<T>,
|
||||||
{
|
{
|
||||||
let colon_idx = parse_id(user_id.as_ref(), &['@'])?;
|
let colon_idx = parse_id(user_id.as_ref(), &['@'])?;
|
||||||
let localpart = &user_id.as_ref()[1..colon_idx.get() as usize];
|
let localpart = &user_id.as_ref()[1..colon_idx.get() as usize];
|
||||||
@ -151,9 +163,10 @@ mod tests {
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde_json::{from_str, to_string};
|
use serde_json::{from_str, to_string};
|
||||||
|
|
||||||
use super::UserId;
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
|
type UserId = super::UserId<Box<str>>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn valid_user_id_from_str() {
|
fn valid_user_id_from_str() {
|
||||||
let user_id = UserId::try_from("@carl:example.com").expect("Failed to create UserId.");
|
let user_id = UserId::try_from("@carl:example.com").expect("Failed to create UserId.");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user