From 622d69884ccdae70bb830a851c8d55e7abf4c848 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 30 May 2020 21:01:03 +0200 Subject: [PATCH] Add borrowed id types --- .builds/msrv.yml | 4 +- src/event_id.rs | 36 +++++++++------ src/lib.rs | 51 ++++++++++++++++----- src/macros.rs | 58 +++++++++++++----------- src/room_alias_id.rs | 19 ++++---- src/room_id.rs | 34 +++++++++----- src/room_id_or_room_alias_id.rs | 45 ++++++++++--------- src/room_version_id.rs | 80 +++++++++++++++++++-------------- src/user_id.rs | 43 +++++++++++------- 9 files changed, 226 insertions(+), 144 deletions(-) diff --git a/.builds/msrv.yml b/.builds/msrv.yml index 0f98a39f..4e7eb631 100644 --- a/.builds/msrv.yml +++ b/.builds/msrv.yml @@ -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 diff --git a/src/event_id.rs b/src/event_id.rs index c0c9c1f1..aa95f931 100644 --- a/src/event_id.rs +++ b/src/event_id.rs @@ -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, +#[derive(Clone, Copy, Debug)] +pub struct EventId { + full_id: T, colon_idx: Option, } -impl EventId { +impl EventId { /// 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 { + pub fn new(server_name: &str) -> Result + where + String: Into, + { 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, + { 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, + { 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(event_id: S) -> Result +fn try_from(event_id: S) -> Result, Error> where - S: AsRef + Into>, + S: AsRef + Into, { 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>; + #[test] fn valid_original_event_id() { assert_eq!( diff --git a/src/lib.rs b/src/lib.rs index 16b6dea6..ae770d04 100644 --- a/src/lib.rs +++ b/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>; +/// 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>; +/// 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>; +/// 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>; +/// 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>; +/// 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>; +/// 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. diff --git a/src/macros.rs b/src/macros.rs index 5ea40a4e..a072a6aa 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -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>> for ::std::string::String { + fn from(id: $id>) -> 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 { + $try_from(s) + } + } + + impl ::std::convert::TryFrom<&str> for $id> { type Error = crate::error::Error; fn try_from(s: &str) -> Result { @@ -14,7 +22,7 @@ macro_rules! common_impls { } } - impl ::std::convert::TryFrom for $id { + impl ::std::convert::TryFrom for $id> { type Error = crate::error::Error; fn try_from(s: String) -> Result { @@ -22,56 +30,56 @@ macro_rules! common_impls { } } - impl ::std::convert::AsRef for $id { + impl> ::std::convert::AsRef for $id { fn as_ref(&self) -> &str { - &self.full_id + self.full_id.as_ref() } } - impl ::std::fmt::Display for $id { + impl ::std::fmt::Display for $id { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "{}", self.full_id) } } - impl ::std::cmp::PartialEq for $id { + impl ::std::cmp::PartialEq for $id { fn eq(&self, other: &Self) -> bool { self.full_id == other.full_id } } - impl ::std::cmp::Eq for $id {} + impl ::std::cmp::Eq for $id {} - impl ::std::cmp::PartialOrd for $id { + impl ::std::cmp::PartialOrd for $id { 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 ::std::cmp::Ord for $id { 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 ::std::hash::Hash for $id { fn hash(&self, state: &mut H) { self.full_id.hash(state); } } #[cfg(feature = "serde")] - impl ::serde::Serialize for $id { + impl> ::serde::Serialize for $id { fn serialize(&self, serializer: S) -> Result 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> { fn deserialize(deserializer: D) -> Result where D: ::serde::Deserializer<'de>, @@ -80,27 +88,27 @@ macro_rules! common_impls { } } - impl ::std::cmp::PartialEq<&str> for $id { + impl> ::std::cmp::PartialEq<&str> for $id { 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> ::std::cmp::PartialEq<$id> for &str { + fn eq(&self, other: &$id) -> bool { + *self == other.full_id.as_ref() } } - impl ::std::cmp::PartialEq<::std::string::String> for $id { + impl> ::std::cmp::PartialEq<::std::string::String> for $id { 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> ::std::cmp::PartialEq<$id> for ::std::string::String { + fn eq(&self, other: &$id) -> bool { + &self[..] == other.full_id.as_ref() } } }; diff --git a/src/room_alias_id.rs b/src/room_alias_id.rs index b8ca6684..d8358631 100644 --- a/src/room_alias_id.rs +++ b/src/room_alias_id.rs @@ -17,30 +17,30 @@ use crate::{error::Error, parse_id}; /// "#ruma:example.com" /// ); /// ``` -#[derive(Clone, Debug)] -pub struct RoomAliasId { - pub(crate) full_id: Box, +#[derive(Clone, Copy, Debug)] +pub struct RoomAliasId { + pub(crate) full_id: T, pub(crate) colon_idx: NonZeroU8, } -impl RoomAliasId { +impl> RoomAliasId { /// 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(room_id: S) -> Result +fn try_from(room_id: S) -> Result, Error> where - S: AsRef + Into>, + S: AsRef + Into, { 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>; + #[test] fn valid_room_alias_id() { assert_eq!( diff --git a/src/room_id.rs b/src/room_id.rs index 4187cc9d..82a4416a 100644 --- a/src/room_id.rs +++ b/src/room_id.rs @@ -17,20 +17,23 @@ use crate::{error::Error, parse_id}; /// "!n8f893n9:example.com" /// ); /// ``` -#[derive(Clone, Debug)] -pub struct RoomId { - pub(crate) full_id: Box, +#[derive(Clone, Copy, Debug)] +pub struct RoomId { + pub(crate) full_id: T, pub(crate) colon_idx: NonZeroU8, } -impl RoomId { +impl RoomId { /// 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 { + pub fn new(server_name: &str) -> Result + where + String: Into, + { 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, + { + &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, + { + &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(room_id: S) -> Result +fn try_from(room_id: S) -> Result, Error> where - S: AsRef + Into>, + S: AsRef + Into, { 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>; + #[test] fn valid_room_id() { assert_eq!( diff --git a/src/room_id_or_room_alias_id.rs b/src/room_id_or_room_alias_id.rs index 00018c82..67c93c80 100644 --- a/src/room_id_or_room_alias_id.rs +++ b/src/room_id_or_room_alias_id.rs @@ -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, +#[derive(Clone, Copy, Debug)] +pub struct RoomIdOrAliasId { + full_id: T, colon_idx: NonZeroU8, } -impl RoomIdOrAliasId { +impl> RoomIdOrAliasId { /// 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` #[cfg(feature = "either")] #[cfg_attr(docsrs, doc(cfg(feature = "either")))] - pub fn into_either(self) -> either::Either { + pub fn into_either(self) -> either::Either, RoomAliasId> { 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(room_id_or_alias_id: S) -> Result +fn try_from(room_id_or_alias_id: S) -> Result, Error> where - S: AsRef + Into>, + S: AsRef + Into, { 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 for RoomIdOrAliasId { - fn from(RoomId { full_id, colon_idx }: RoomId) -> Self { +impl From> for RoomIdOrAliasId { + fn from(RoomId { full_id, colon_idx }: RoomId) -> Self { Self { full_id, colon_idx } } } -impl From for RoomIdOrAliasId { - fn from(RoomAliasId { full_id, colon_idx }: RoomAliasId) -> Self { +impl From> for RoomIdOrAliasId { + fn from(RoomAliasId { full_id, colon_idx }: RoomAliasId) -> Self { Self { full_id, colon_idx } } } -impl TryFrom for RoomId { - type Error = RoomAliasId; +impl> TryFrom> for RoomId { + type Error = RoomAliasId; - fn try_from(id: RoomIdOrAliasId) -> Result { + fn try_from(id: RoomIdOrAliasId) -> Result, RoomAliasId> { match id.variant() { Variant::RoomId => Ok(RoomId { full_id: id.full_id, @@ -132,10 +132,10 @@ impl TryFrom for RoomId { } } -impl TryFrom for RoomAliasId { - type Error = RoomId; +impl> TryFrom> for RoomAliasId { + type Error = RoomId; - fn try_from(id: RoomIdOrAliasId) -> Result { + fn try_from(id: RoomIdOrAliasId) -> Result, RoomId> { 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>; + #[test] fn valid_room_id_or_alias_id_with_a_room_alias_id() { assert_eq!( diff --git a/src/room_version_id.rs b/src/room_version_id.rs index bcffda3d..9b7239e1 100644 --- a/src/room_version_id.rs +++ b/src/room_version_id.rs @@ -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(InnerRoomVersionId); /// 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 { /// A version 1 room. Version1, @@ -50,10 +50,10 @@ enum InnerRoomVersionId { Version6, /// A custom room version. - Custom(Box), + Custom(T), } -impl RoomVersionId { +impl RoomVersionId { /// 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, + { 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 for String { - fn from(id: RoomVersionId) -> Self { +impl From>> for String { + fn from(id: RoomVersionId>) -> Self { match id.0 { InnerRoomVersionId::Version1 => "1".to_owned(), InnerRoomVersionId::Version2 => "2".to_owned(), @@ -147,7 +150,7 @@ impl From for String { } } -impl AsRef for RoomVersionId { +impl> AsRef for RoomVersionId { fn as_ref(&self) -> &str { match &self.0 { InnerRoomVersionId::Version1 => "1", @@ -156,31 +159,31 @@ impl AsRef 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> Display for RoomVersionId { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{}", self.as_ref()) } } -impl PartialOrd for RoomVersionId { - fn partial_cmp(&self, other: &RoomVersionId) -> Option { +impl> PartialOrd for RoomVersionId { + fn partial_cmp(&self, other: &RoomVersionId) -> Option { self.as_ref().partial_cmp(other.as_ref()) } } -impl Ord for RoomVersionId { +impl> Ord for RoomVersionId { fn cmp(&self, other: &Self) -> Ordering { self.as_ref().cmp(other.as_ref()) } } #[cfg(feature = "serde")] -impl Serialize for RoomVersionId { +impl> Serialize for RoomVersionId { fn serialize(&self, serializer: S) -> Result 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> { fn deserialize(deserializer: D) -> Result 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(room_version_id: S) -> Result +fn try_from(room_version_id: S) -> Result, Error> where - S: AsRef + Into>, + S: AsRef + Into, { 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 { + try_from(s) + } +} + +impl TryFrom<&str> for RoomVersionId> { type Error = crate::error::Error; fn try_from(s: &str) -> Result { @@ -232,7 +243,7 @@ impl TryFrom<&str> for RoomVersionId { } } -impl TryFrom for RoomVersionId { +impl TryFrom for RoomVersionId> { type Error = crate::error::Error; fn try_from(s: String) -> Result { @@ -240,26 +251,26 @@ impl TryFrom for RoomVersionId { } } -impl PartialEq<&str> for RoomVersionId { +impl> PartialEq<&str> for RoomVersionId { fn eq(&self, other: &&str) -> bool { self.as_ref() == *other } } -impl PartialEq for &str { - fn eq(&self, other: &RoomVersionId) -> bool { +impl> PartialEq> for &str { + fn eq(&self, other: &RoomVersionId) -> bool { *self == other.as_ref() } } -impl PartialEq for RoomVersionId { +impl> PartialEq for RoomVersionId { fn eq(&self, other: &String) -> bool { self.as_ref() == other } } -impl PartialEq for String { - fn eq(&self, other: &RoomVersionId) -> bool { +impl> PartialEq> for String { + fn eq(&self, other: &RoomVersionId) -> 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>; + #[test] fn valid_version_1_room_version_id() { assert_eq!( diff --git a/src/user_id.rs b/src/user_id.rs index 5bb8047c..f4b2962c 100644 --- a/src/user_id.rs +++ b/src/user_id.rs @@ -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, +#[derive(Clone, Copy, Debug)] +pub struct UserId { + 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 UserId { /// 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 { + pub fn new(server_name: &str) -> Result + where + String: Into, + { 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 + Into>, + id: impl AsRef + Into, server_name: &str, - ) -> Result { + ) -> Result + where + String: Into, + { 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, + { + &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, + { + &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(user_id: S) -> Result +fn try_from(user_id: S) -> Result, Error> where - S: AsRef + Into>, + S: AsRef + Into, { 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>; + #[test] fn valid_user_id_from_str() { let user_id = UserId::try_from("@carl:example.com").expect("Failed to create UserId.");