Add borrowed id types
This commit is contained in:
parent
06c52c2abb
commit
622d69884c
@ -6,8 +6,8 @@ sources:
|
||||
tasks:
|
||||
- rustup: |
|
||||
# We specify --profile minimal because we'd otherwise download docs
|
||||
rustup toolchain install 1.36.0 --profile minimal
|
||||
rustup default 1.36.0
|
||||
rustup toolchain install 1.42.0 --profile minimal
|
||||
rustup default 1.42.0
|
||||
- test: |
|
||||
cd ruma-identifiers
|
||||
|
||||
|
@ -37,13 +37,13 @@ use crate::{error::Error, parse_id, validate_id};
|
||||
/// "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg"
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EventId {
|
||||
full_id: Box<str>,
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct EventId<T> {
|
||||
full_id: T,
|
||||
colon_idx: Option<NonZeroU8>,
|
||||
}
|
||||
|
||||
impl EventId {
|
||||
impl<T> EventId<T> {
|
||||
/// 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
|
||||
/// as used by Matrix room versions 1 and 2.
|
||||
@ -52,7 +52,10 @@ impl EventId {
|
||||
/// parsed as a valid host.
|
||||
#[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};
|
||||
|
||||
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
|
||||
/// versions 1 and 2, this is the "localpart" that precedes the homeserver. For later formats,
|
||||
/// 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 {
|
||||
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.
|
||||
///
|
||||
/// 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
|
||||
.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
|
||||
/// 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
|
||||
S: AsRef<str> + Into<Box<str>>,
|
||||
S: AsRef<str> + Into<T>,
|
||||
{
|
||||
if event_id.as_ref().contains(':') {
|
||||
let colon_idx = parse_id(event_id.as_ref(), &['$'])?;
|
||||
@ -121,9 +130,10 @@ mod tests {
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_json::{from_str, to_string};
|
||||
|
||||
use super::EventId;
|
||||
use crate::error::Error;
|
||||
|
||||
type EventId = super::EventId<Box<str>>;
|
||||
|
||||
#[test]
|
||||
fn valid_original_event_id() {
|
||||
assert_eq!(
|
||||
|
51
src/lib.rs
51
src/lib.rs
@ -5,7 +5,7 @@
|
||||
#![deny(
|
||||
missing_copy_implementations,
|
||||
missing_debug_implementations,
|
||||
missing_docs
|
||||
//missing_docs
|
||||
)]
|
||||
// Since we support Rust 1.36.0, we can't apply this suggestion yet
|
||||
#![allow(clippy::use_self)]
|
||||
@ -17,25 +17,52 @@ use std::num::NonZeroU8;
|
||||
use serde::de::{self, Deserialize as _, Deserializer, Unexpected};
|
||||
|
||||
#[doc(inline)]
|
||||
pub use crate::{
|
||||
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,
|
||||
};
|
||||
pub use crate::{error::Error, server_name::is_valid_server_name};
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
pub mod device_id;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/// 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.
|
||||
const MAX_BYTES: usize = 255;
|
||||
/// The minimum number of characters an ID can be.
|
||||
|
@ -1,12 +1,20 @@
|
||||
macro_rules! common_impls {
|
||||
($id:ident, $try_from:ident, $desc:literal) => {
|
||||
impl ::std::convert::From<$id> for ::std::string::String {
|
||||
fn from(id: $id) -> Self {
|
||||
impl ::std::convert::From<$id<Box<str>>> for ::std::string::String {
|
||||
fn from(id: $id<Box<str>>) -> Self {
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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 {
|
||||
&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 {
|
||||
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 {
|
||||
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> {
|
||||
::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 {
|
||||
::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) {
|
||||
self.full_id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[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>
|
||||
where
|
||||
S: ::serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.full_id)
|
||||
serializer.serialize_str(self.full_id.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[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>
|
||||
where
|
||||
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 {
|
||||
&self.full_id[..] == *other
|
||||
self.full_id.as_ref() == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::cmp::PartialEq<$id> for &str {
|
||||
fn eq(&self, other: &$id) -> bool {
|
||||
*self == &other.full_id[..]
|
||||
impl<T: AsRef<str>> ::std::cmp::PartialEq<$id<T>> for &str {
|
||||
fn eq(&self, other: &$id<T>) -> bool {
|
||||
*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 {
|
||||
&self.full_id[..] == &other[..]
|
||||
self.full_id.as_ref() == &other[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::cmp::PartialEq<$id> for ::std::string::String {
|
||||
fn eq(&self, other: &$id) -> bool {
|
||||
&self[..] == &other.full_id[..]
|
||||
impl<T: AsRef<str>> ::std::cmp::PartialEq<$id<T>> for ::std::string::String {
|
||||
fn eq(&self, other: &$id<T>) -> bool {
|
||||
&self[..] == other.full_id.as_ref()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -17,30 +17,30 @@ use crate::{error::Error, parse_id};
|
||||
/// "#ruma:example.com"
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RoomAliasId {
|
||||
pub(crate) full_id: Box<str>,
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RoomAliasId<T> {
|
||||
pub(crate) full_id: T,
|
||||
pub(crate) colon_idx: NonZeroU8,
|
||||
}
|
||||
|
||||
impl RoomAliasId {
|
||||
impl<T: AsRef<str>> RoomAliasId<T> {
|
||||
/// Returns the room's alias.
|
||||
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.
|
||||
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.
|
||||
///
|
||||
/// 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
|
||||
S: AsRef<str> + Into<Box<str>>,
|
||||
S: AsRef<str> + Into<T>,
|
||||
{
|
||||
let colon_idx = parse_id(room_id.as_ref(), &['#'])?;
|
||||
|
||||
@ -59,9 +59,10 @@ mod tests {
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_json::{from_str, to_string};
|
||||
|
||||
use super::RoomAliasId;
|
||||
use crate::error::Error;
|
||||
|
||||
type RoomAliasId = super::RoomAliasId<Box<str>>;
|
||||
|
||||
#[test]
|
||||
fn valid_room_alias_id() {
|
||||
assert_eq!(
|
||||
|
@ -17,20 +17,23 @@ use crate::{error::Error, parse_id};
|
||||
/// "!n8f893n9:example.com"
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RoomId {
|
||||
pub(crate) full_id: Box<str>,
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RoomId<T> {
|
||||
pub(crate) full_id: T,
|
||||
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
|
||||
/// 18 random ASCII characters.
|
||||
///
|
||||
/// Fails if the given homeserver cannot be parsed as a valid host.
|
||||
#[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};
|
||||
|
||||
if !is_valid_server_name(server_name) {
|
||||
@ -45,22 +48,28 @@ impl RoomId {
|
||||
}
|
||||
|
||||
/// Returns the rooms's unique ID.
|
||||
pub fn localpart(&self) -> &str {
|
||||
&self.full_id[1..self.colon_idx.get() as usize]
|
||||
pub fn localpart(&self) -> &str
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
&self.full_id.as_ref()[1..self.colon_idx.get() as usize]
|
||||
}
|
||||
|
||||
/// Returns the server name of the room ID.
|
||||
pub fn server_name(&self) -> &str {
|
||||
&self.full_id[self.colon_idx.get() as usize + 1..]
|
||||
pub fn server_name(&self) -> &str
|
||||
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.
|
||||
///
|
||||
/// 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
|
||||
S: AsRef<str> + Into<Box<str>>,
|
||||
S: AsRef<str> + Into<T>,
|
||||
{
|
||||
let colon_idx = parse_id(room_id.as_ref(), &['!'])?;
|
||||
|
||||
@ -79,9 +88,10 @@ mod tests {
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_json::{from_str, to_string};
|
||||
|
||||
use super::RoomId;
|
||||
use crate::error::Error;
|
||||
|
||||
type RoomId = super::RoomId<Box<str>>;
|
||||
|
||||
#[test]
|
||||
fn valid_room_id() {
|
||||
assert_eq!(
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
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.
|
||||
///
|
||||
@ -23,21 +23,21 @@ use crate::{error::Error, parse_id, RoomAliasId, RoomId};
|
||||
/// "!n8f893n9:example.com"
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RoomIdOrAliasId {
|
||||
full_id: Box<str>,
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RoomIdOrAliasId<T> {
|
||||
full_id: T,
|
||||
colon_idx: NonZeroU8,
|
||||
}
|
||||
|
||||
impl RoomIdOrAliasId {
|
||||
impl<T: AsRef<str>> RoomIdOrAliasId<T> {
|
||||
/// Returns the local part (everything after the `!` or `#` and before the first colon).
|
||||
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.
|
||||
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 `'!'`)
|
||||
@ -53,7 +53,7 @@ impl RoomIdOrAliasId {
|
||||
/// Turn this `RoomIdOrAliasId` into `Either<RoomId, RoomAliasId>`
|
||||
#[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() {
|
||||
Variant::RoomId => either::Either::Left(RoomId {
|
||||
full_id: self.full_id,
|
||||
@ -67,7 +67,7 @@ impl RoomIdOrAliasId {
|
||||
}
|
||||
|
||||
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::RoomAliasId,
|
||||
_ => unsafe { unreachable_unchecked() },
|
||||
@ -86,9 +86,9 @@ enum Variant {
|
||||
/// 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.
|
||||
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
|
||||
S: AsRef<str> + Into<Box<str>>,
|
||||
S: AsRef<str> + Into<T>,
|
||||
{
|
||||
let colon_idx = parse_id(room_id_or_alias_id.as_ref(), &['#', '!'])?;
|
||||
Ok(RoomIdOrAliasId {
|
||||
@ -103,22 +103,22 @@ common_impls!(
|
||||
"a Matrix room ID or room alias ID"
|
||||
);
|
||||
|
||||
impl From<RoomId> for RoomIdOrAliasId {
|
||||
fn from(RoomId { full_id, colon_idx }: RoomId) -> Self {
|
||||
impl<T> From<RoomId<T>> for RoomIdOrAliasId<T> {
|
||||
fn from(RoomId { full_id, colon_idx }: RoomId<T>) -> Self {
|
||||
Self { full_id, colon_idx }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RoomAliasId> for RoomIdOrAliasId {
|
||||
fn from(RoomAliasId { full_id, colon_idx }: RoomAliasId) -> Self {
|
||||
impl<T> From<RoomAliasId<T>> for RoomIdOrAliasId<T> {
|
||||
fn from(RoomAliasId { full_id, colon_idx }: RoomAliasId<T>) -> Self {
|
||||
Self { full_id, colon_idx }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RoomIdOrAliasId> for RoomId {
|
||||
type Error = RoomAliasId;
|
||||
impl<T: AsRef<str>> TryFrom<RoomIdOrAliasId<T>> for RoomId<T> {
|
||||
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() {
|
||||
Variant::RoomId => Ok(RoomId {
|
||||
full_id: id.full_id,
|
||||
@ -132,10 +132,10 @@ impl TryFrom<RoomIdOrAliasId> for RoomId {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RoomIdOrAliasId> for RoomAliasId {
|
||||
type Error = RoomId;
|
||||
impl<T: AsRef<str>> TryFrom<RoomIdOrAliasId<T>> for RoomAliasId<T> {
|
||||
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() {
|
||||
Variant::RoomAliasId => Ok(RoomAliasId {
|
||||
full_id: id.full_id,
|
||||
@ -156,9 +156,10 @@ mod tests {
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_json::{from_str, to_string};
|
||||
|
||||
use super::RoomIdOrAliasId;
|
||||
use crate::error::Error;
|
||||
|
||||
type RoomIdOrAliasId = super::RoomIdOrAliasId<Box<str>>;
|
||||
|
||||
#[test]
|
||||
fn valid_room_id_or_alias_id_with_a_room_alias_id() {
|
||||
assert_eq!(
|
||||
|
@ -24,13 +24,13 @@ const MAX_CODE_POINTS: usize = 32;
|
||||
/// # use ruma_identifiers::RoomVersionId;
|
||||
/// assert_eq!(RoomVersionId::try_from("1").unwrap().as_ref(), "1");
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct RoomVersionId(InnerRoomVersionId);
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct RoomVersionId<T>(InnerRoomVersionId<T>);
|
||||
|
||||
/// Possibile values for room version, distinguishing between official Matrix versions and custom
|
||||
/// versions.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
enum InnerRoomVersionId {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
enum InnerRoomVersionId<T> {
|
||||
/// A version 1 room.
|
||||
Version1,
|
||||
|
||||
@ -50,10 +50,10 @@ enum InnerRoomVersionId {
|
||||
Version6,
|
||||
|
||||
/// A custom room version.
|
||||
Custom(Box<str>),
|
||||
Custom(T),
|
||||
}
|
||||
|
||||
impl RoomVersionId {
|
||||
impl<T> RoomVersionId<T> {
|
||||
/// Creates a version 1 room ID.
|
||||
pub fn version_1() -> Self {
|
||||
Self(InnerRoomVersionId::Version1)
|
||||
@ -85,7 +85,10 @@ impl RoomVersionId {
|
||||
}
|
||||
|
||||
/// 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()))
|
||||
}
|
||||
|
||||
@ -104,37 +107,37 @@ impl RoomVersionId {
|
||||
|
||||
/// Whether or not this is a version 1 room.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
pub fn is_version_6(&self) -> bool {
|
||||
self.0 == InnerRoomVersionId::Version5
|
||||
matches!(self.0, InnerRoomVersionId::Version5)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RoomVersionId> for String {
|
||||
fn from(id: RoomVersionId) -> Self {
|
||||
impl From<RoomVersionId<Box<str>>> for String {
|
||||
fn from(id: RoomVersionId<Box<str>>) -> Self {
|
||||
match id.0 {
|
||||
InnerRoomVersionId::Version1 => "1".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 {
|
||||
match &self.0 {
|
||||
InnerRoomVersionId::Version1 => "1",
|
||||
@ -156,31 +159,31 @@ impl AsRef<str> for RoomVersionId {
|
||||
InnerRoomVersionId::Version4 => "4",
|
||||
InnerRoomVersionId::Version5 => "5",
|
||||
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 {
|
||||
write!(f, "{}", self.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for RoomVersionId {
|
||||
fn partial_cmp(&self, other: &RoomVersionId) -> Option<Ordering> {
|
||||
impl<T: PartialEq + AsRef<str>> PartialOrd for RoomVersionId<T> {
|
||||
fn partial_cmp(&self, other: &RoomVersionId<T>) -> Option<Ordering> {
|
||||
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 {
|
||||
self.as_ref().cmp(other.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[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>
|
||||
where
|
||||
S: Serializer,
|
||||
@ -190,7 +193,7 @@ impl Serialize for RoomVersionId {
|
||||
}
|
||||
|
||||
#[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>
|
||||
where
|
||||
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.
|
||||
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
|
||||
S: AsRef<str> + Into<Box<str>>,
|
||||
S: AsRef<str> + Into<T>,
|
||||
{
|
||||
let version = match room_version_id.as_ref() {
|
||||
"1" => RoomVersionId(InnerRoomVersionId::Version1),
|
||||
@ -224,7 +227,15 @@ where
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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 {
|
||||
self.as_ref() == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<RoomVersionId> for &str {
|
||||
fn eq(&self, other: &RoomVersionId) -> bool {
|
||||
impl<T: AsRef<str>> PartialEq<RoomVersionId<T>> for &str {
|
||||
fn eq(&self, other: &RoomVersionId<T>) -> bool {
|
||||
*self == other.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for RoomVersionId {
|
||||
impl<T: AsRef<str>> PartialEq<String> for RoomVersionId<T> {
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
self.as_ref() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<RoomVersionId> for String {
|
||||
fn eq(&self, other: &RoomVersionId) -> bool {
|
||||
impl<T: AsRef<str>> PartialEq<RoomVersionId<T>> for String {
|
||||
fn eq(&self, other: &RoomVersionId<T>) -> bool {
|
||||
self == other.as_ref()
|
||||
}
|
||||
}
|
||||
@ -271,9 +282,10 @@ mod tests {
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_json::{from_str, to_string};
|
||||
|
||||
use super::RoomVersionId;
|
||||
use crate::error::Error;
|
||||
|
||||
type RoomVersionId = super::RoomVersionId<Box<str>>;
|
||||
|
||||
#[test]
|
||||
fn valid_version_1_room_version_id() {
|
||||
assert_eq!(
|
||||
|
@ -17,9 +17,9 @@ use crate::{error::Error, is_valid_server_name, parse_id};
|
||||
/// "@carl:example.com"
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UserId {
|
||||
full_id: Box<str>,
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UserId<T> {
|
||||
full_id: T,
|
||||
colon_idx: NonZeroU8,
|
||||
/// Whether this user id is a historical one.
|
||||
///
|
||||
@ -29,14 +29,17 @@ pub struct UserId {
|
||||
is_historical: bool,
|
||||
}
|
||||
|
||||
impl UserId {
|
||||
impl<T> UserId<T> {
|
||||
/// Attempts to generate a `UserId` for the given origin server with a localpart consisting of
|
||||
/// 12 random ASCII characters.
|
||||
///
|
||||
/// Fails if the given homeserver cannot be parsed as a valid host.
|
||||
#[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;
|
||||
|
||||
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
|
||||
/// the `@` prefix.
|
||||
pub fn parse_with_server_name(
|
||||
id: impl AsRef<str> + Into<Box<str>>,
|
||||
id: impl AsRef<str> + Into<T>,
|
||||
server_name: &str,
|
||||
) -> Result<Self, Error> {
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
String: Into<T>,
|
||||
{
|
||||
let id_str = id.as_ref();
|
||||
|
||||
if id_str.starts_with('@') {
|
||||
try_from(id.into())
|
||||
try_from(id)
|
||||
} else {
|
||||
let is_fully_conforming = localpart_is_fully_comforming(id_str)?;
|
||||
if !is_valid_server_name(server_name) {
|
||||
@ -81,13 +87,19 @@ impl UserId {
|
||||
}
|
||||
|
||||
/// Returns the user's localpart.
|
||||
pub fn localpart(&self) -> &str {
|
||||
&self.full_id[1..self.colon_idx.get() as usize]
|
||||
pub fn localpart(&self) -> &str
|
||||
where
|
||||
T: AsRef<str>,
|
||||
{
|
||||
&self.full_id.as_ref()[1..self.colon_idx.get() as usize]
|
||||
}
|
||||
|
||||
/// Returns the server name of the user ID.
|
||||
pub fn server_name(&self) -> &str {
|
||||
&self.full_id[self.colon_idx.get() as usize + 1..]
|
||||
pub fn server_name(&self) -> &str
|
||||
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
|
||||
@ -101,9 +113,9 @@ impl UserId {
|
||||
/// 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.
|
||||
fn try_from<S>(user_id: S) -> Result<UserId, Error>
|
||||
fn try_from<S, T>(user_id: S) -> Result<UserId<T>, Error>
|
||||
where
|
||||
S: AsRef<str> + Into<Box<str>>,
|
||||
S: AsRef<str> + Into<T>,
|
||||
{
|
||||
let colon_idx = parse_id(user_id.as_ref(), &['@'])?;
|
||||
let localpart = &user_id.as_ref()[1..colon_idx.get() as usize];
|
||||
@ -151,9 +163,10 @@ mod tests {
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_json::{from_str, to_string};
|
||||
|
||||
use super::UserId;
|
||||
use crate::error::Error;
|
||||
|
||||
type UserId = super::UserId<Box<str>>;
|
||||
|
||||
#[test]
|
||||
fn valid_user_id_from_str() {
|
||||
let user_id = UserId::try_from("@carl:example.com").expect("Failed to create UserId.");
|
||||
|
Loading…
x
Reference in New Issue
Block a user