diff --git a/ruma-client-api/src/r0/account/register.rs b/ruma-client-api/src/r0/account/register.rs index 9a5c667f..ece32331 100644 --- a/ruma-client-api/src/r0/account/register.rs +++ b/ruma-client-api/src/r0/account/register.rs @@ -35,7 +35,7 @@ ruma_api! { /// If this does not correspond to a known client device, a new device will be created. /// The server will auto-generate a device_id if this is not specified. #[serde(skip_serializing_if = "Option::is_none")] - pub device_id: Option, + pub device_id: Option>, /// A display name to assign to the newly-created device. /// @@ -78,7 +78,7 @@ ruma_api! { /// ID of the registered device. /// /// Will be the same as the corresponding parameter in the request, if one was specified. - pub device_id: Option, + pub device_id: Option>, } error: UiaaResponse diff --git a/ruma-client-api/src/r0/device.rs b/ruma-client-api/src/r0/device.rs index 685dab81..a49718be 100644 --- a/ruma-client-api/src/r0/device.rs +++ b/ruma-client-api/src/r0/device.rs @@ -15,7 +15,7 @@ pub mod update_device; #[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)] pub struct Device { /// Device ID - pub device_id: DeviceId, + pub device_id: Box, /// Public display name of the device. pub display_name: Option, diff --git a/ruma-client-api/src/r0/device/delete_device.rs b/ruma-client-api/src/r0/device/delete_device.rs index ca99100f..9f4084b2 100644 --- a/ruma-client-api/src/r0/device/delete_device.rs +++ b/ruma-client-api/src/r0/device/delete_device.rs @@ -18,7 +18,7 @@ ruma_api! { request: { /// The device to delete. #[ruma_api(path)] - pub device_id: DeviceId, + pub device_id: Box, /// Additional authentication information for the user-interactive authentication API. #[serde(skip_serializing_if = "Option::is_none")] diff --git a/ruma-client-api/src/r0/device/delete_devices.rs b/ruma-client-api/src/r0/device/delete_devices.rs index 72f3eaa0..df3cd7fc 100644 --- a/ruma-client-api/src/r0/device/delete_devices.rs +++ b/ruma-client-api/src/r0/device/delete_devices.rs @@ -17,7 +17,7 @@ ruma_api! { request: { /// List of devices to delete. - pub devices: Vec, + pub devices: Vec>, /// Additional authentication information for the user-interactive authentication API. #[serde(skip_serializing_if = "Option::is_none")] diff --git a/ruma-client-api/src/r0/device/get_device.rs b/ruma-client-api/src/r0/device/get_device.rs index 2b6b01c5..8a57b59a 100644 --- a/ruma-client-api/src/r0/device/get_device.rs +++ b/ruma-client-api/src/r0/device/get_device.rs @@ -17,7 +17,7 @@ ruma_api! { request: { /// The device to retrieve. #[ruma_api(path)] - pub device_id: DeviceId, + pub device_id: Box, } response: { diff --git a/ruma-client-api/src/r0/device/update_device.rs b/ruma-client-api/src/r0/device/update_device.rs index ff874e5d..b4c38c79 100644 --- a/ruma-client-api/src/r0/device/update_device.rs +++ b/ruma-client-api/src/r0/device/update_device.rs @@ -16,7 +16,7 @@ ruma_api! { request: { /// The device to update. #[ruma_api(path)] - pub device_id: DeviceId, + pub device_id: Box, /// The new display name for this device. If this is `None`, the display name won't be /// changed. diff --git a/ruma-client-api/src/r0/keys.rs b/ruma-client-api/src/r0/keys.rs index ad104b67..b2769b90 100644 --- a/ruma-client-api/src/r0/keys.rs +++ b/ruma-client-api/src/r0/keys.rs @@ -60,7 +60,7 @@ impl TryFrom<&'_ str> for KeyAlgorithm { /// A key algorithm and a device id, combined with a ':' #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct AlgorithmAndDeviceId(pub KeyAlgorithm, pub DeviceId); +pub struct AlgorithmAndDeviceId(pub KeyAlgorithm, pub Box); impl Display for AlgorithmAndDeviceId { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -102,7 +102,7 @@ impl<'de> Deserialize<'de> for AlgorithmAndDeviceId { let algorithm_result = KeyAlgorithm::try_from(parts[0]); match algorithm_result { - Ok(algorithm) => Ok(AlgorithmAndDeviceId(algorithm, parts[1].to_string())), + Ok(algorithm) => Ok(AlgorithmAndDeviceId(algorithm, parts[1].into())), Err(_) => { Err(de::Error::invalid_value(Unexpected::Str(parts[0]), &"valid key algorithm")) } @@ -117,7 +117,7 @@ pub struct DeviceKeys { pub user_id: UserId, /// The ID of the device these keys belong to. Must match the device ID used when logging in. - pub device_id: DeviceId, + pub device_id: Box, /// The encryption algorithms supported by this device. pub algorithms: Vec, diff --git a/ruma-client-api/src/r0/keys/claim_keys.rs b/ruma-client-api/src/r0/keys/claim_keys.rs index 50457619..4cd08281 100644 --- a/ruma-client-api/src/r0/keys/claim_keys.rs +++ b/ruma-client-api/src/r0/keys/claim_keys.rs @@ -31,7 +31,7 @@ ruma_api! { pub timeout: Option, /// The keys to be claimed. - pub one_time_keys: BTreeMap>, + pub one_time_keys: BTreeMap, KeyAlgorithm>>, } response: { @@ -40,8 +40,11 @@ ruma_api! { pub failures: BTreeMap, /// One-time keys for the queried devices. - pub one_time_keys: BTreeMap>>, + pub one_time_keys: BTreeMap, } error: crate::Error } + +/// The one-time keys for a given device. +pub type OneTimeKeys = BTreeMap, BTreeMap>; diff --git a/ruma-client-api/src/r0/keys/get_keys.rs b/ruma-client-api/src/r0/keys/get_keys.rs index 949b8570..8f98c17b 100644 --- a/ruma-client-api/src/r0/keys/get_keys.rs +++ b/ruma-client-api/src/r0/keys/get_keys.rs @@ -30,7 +30,7 @@ ruma_api! { /// The keys to be downloaded. An empty list indicates all devices for /// the corresponding user. - pub device_keys: BTreeMap>, + pub device_keys: BTreeMap>>, /// If the client is fetching keys as a result of a device update /// received in a sync request, this should be the 'since' token of that @@ -48,7 +48,7 @@ ruma_api! { pub failures: BTreeMap, /// Information on the queried devices. - pub device_keys: BTreeMap>, + pub device_keys: BTreeMap, DeviceKeys>>, } error: crate::Error diff --git a/ruma-client-api/src/r0/session/login.rs b/ruma-client-api/src/r0/session/login.rs index 85ec256c..3d972b89 100644 --- a/ruma-client-api/src/r0/session/login.rs +++ b/ruma-client-api/src/r0/session/login.rs @@ -27,7 +27,7 @@ ruma_api! { /// ID of the client device #[serde(skip_serializing_if = "Option::is_none")] - pub device_id: Option, + pub device_id: Option>, /// A display name to assign to the newly-created device. Ignored if device_id corresponds /// to a known device. diff --git a/ruma-client-api/src/r0/to_device.rs b/ruma-client-api/src/r0/to_device.rs index 73f6df51..b3412f58 100644 --- a/ruma-client-api/src/r0/to_device.rs +++ b/ruma-client-api/src/r0/to_device.rs @@ -17,7 +17,7 @@ pub mod send_event_to_device; #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum DeviceIdOrAllDevices { /// Represents a device Id for one of a user's devices. - DeviceId(DeviceId), + DeviceId(Box), /// Represents all devices for a user. AllDevices, @@ -40,7 +40,7 @@ impl TryFrom<&str> for DeviceIdOrAllDevices { } else if "*" == device_id_or_all_devices { Ok(DeviceIdOrAllDevices::AllDevices) } else { - Ok(DeviceIdOrAllDevices::DeviceId(device_id_or_all_devices.to_string())) + Ok(DeviceIdOrAllDevices::DeviceId(device_id_or_all_devices.into())) } } } diff --git a/ruma-events/src/direct.rs b/ruma-events/src/direct.rs index ec9ab6a9..08d5c3c8 100644 --- a/ruma-events/src/direct.rs +++ b/ruma-events/src/direct.rs @@ -38,7 +38,7 @@ impl DerefMut for DirectEventContent { mod tests { use std::{collections::BTreeMap, convert::TryFrom}; - use ruma_identifiers::{RoomId, ServerNameRef, UserId}; + use ruma_identifiers::{RoomId, ServerName, UserId}; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use super::{DirectEvent, DirectEventContent}; @@ -47,7 +47,7 @@ mod tests { #[test] fn serialization() { let mut content = DirectEventContent(BTreeMap::new()); - let server_name = ServerNameRef::try_from("ruma.io").unwrap(); + let server_name = <&ServerName>::try_from("ruma.io").unwrap(); let alice = UserId::new(server_name); let room = vec![RoomId::new(server_name)]; @@ -66,7 +66,7 @@ mod tests { #[test] fn deserialization() { - let server_name = ServerNameRef::try_from("ruma.io").unwrap(); + let server_name = <&ServerName>::try_from("ruma.io").unwrap(); let alice = UserId::new(server_name); let rooms = vec![RoomId::new(server_name), RoomId::new(server_name)]; diff --git a/ruma-events/src/key/verification/request.rs b/ruma-events/src/key/verification/request.rs index 14ddea75..262c20e9 100644 --- a/ruma-events/src/key/verification/request.rs +++ b/ruma-events/src/key/verification/request.rs @@ -19,7 +19,7 @@ pub type RequestEvent = BasicEvent; #[ruma_event(type = "m.key.verification.request")] pub struct RequestEventContent { /// The device ID which is initiating the request. - pub from_device: DeviceId, + pub from_device: Box, /// An opaque identifier for the verification request. /// diff --git a/ruma-events/src/key/verification/start.rs b/ruma-events/src/key/verification/start.rs index ecd80c3e..acc361b1 100644 --- a/ruma-events/src/key/verification/start.rs +++ b/ruma-events/src/key/verification/start.rs @@ -29,7 +29,7 @@ pub enum StartEventContent { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct MSasV1Content { /// The device ID which is initiating the process. - pub(crate) from_device: DeviceId, + pub(crate) from_device: Box, /// An opaque identifier for the verification process. /// @@ -63,7 +63,7 @@ pub struct MSasV1Content { #[derive(Clone, Debug, Deserialize)] pub struct MSasV1ContentOptions { /// The device ID which is initiating the process. - pub from_device: DeviceId, + pub from_device: Box, /// An opaque identifier for the verification process. /// @@ -270,7 +270,7 @@ mod tests { key_agreement_protocols, message_authentication_codes, short_authentication_string, - }) if from_device == "123" + }) if from_device.as_ref() == "123" && transaction_id == "456" && hashes == vec![HashAlgorithm::Sha256] && key_agreement_protocols == vec![KeyAgreementProtocol::Curve25519] @@ -305,7 +305,7 @@ mod tests { message_authentication_codes, short_authentication_string, }) - } if from_device == "123" + } if from_device.as_ref() == "123" && transaction_id == "456" && hashes == vec![HashAlgorithm::Sha256] && key_agreement_protocols == vec![KeyAgreementProtocol::Curve25519] diff --git a/ruma-events/src/room/encrypted.rs b/ruma-events/src/room/encrypted.rs index 3e5ad939..86c59ad4 100644 --- a/ruma-events/src/room/encrypted.rs +++ b/ruma-events/src/room/encrypted.rs @@ -60,7 +60,7 @@ pub struct MegolmV1AesSha2Content { pub sender_key: String, /// The ID of the sending device. - pub device_id: DeviceId, + pub device_id: Box, /// The ID of the session used to encrypt the message. pub session_id: String, @@ -117,7 +117,7 @@ mod tests { session_id, }) if ciphertext == "ciphertext" && sender_key == "sender_key" - && device_id == "device_id" + && device_id.as_ref() == "device_id" && session_id == "session_id" ); } diff --git a/ruma-events/src/room/pinned_events.rs b/ruma-events/src/room/pinned_events.rs index 0fc04302..66f29755 100644 --- a/ruma-events/src/room/pinned_events.rs +++ b/ruma-events/src/room/pinned_events.rs @@ -24,7 +24,7 @@ mod tests { time::{Duration, UNIX_EPOCH}, }; - use ruma_identifiers::{EventId, RoomId, ServerNameRef, UserId}; + use ruma_identifiers::{EventId, RoomId, ServerName, UserId}; use serde_json::to_string; use super::PinnedEventsEventContent; @@ -33,7 +33,7 @@ mod tests { #[test] fn serialization_deserialization() { let mut content: PinnedEventsEventContent = PinnedEventsEventContent { pinned: Vec::new() }; - let server_name = ServerNameRef::try_from("example.com").unwrap(); + let server_name = <&ServerName>::try_from("example.com").unwrap(); content.pinned.push(EventId::new(server_name)); content.pinned.push(EventId::new(server_name)); diff --git a/ruma-events/src/room_key_request.rs b/ruma-events/src/room_key_request.rs index afd791a6..1d748ff0 100644 --- a/ruma-events/src/room_key_request.rs +++ b/ruma-events/src/room_key_request.rs @@ -26,7 +26,7 @@ pub struct RoomKeyRequestEventContent { pub body: Option, /// ID of the device requesting the key. - pub requesting_device_id: DeviceId, + pub requesting_device_id: Box, /// A random string uniquely identifying the request for a key. /// diff --git a/ruma-identifiers/src/device_id.rs b/ruma-identifiers/src/device_id.rs index d526f066..e6993390 100644 --- a/ruma-identifiers/src/device_id.rs +++ b/ruma-identifiers/src/device_id.rs @@ -7,12 +7,12 @@ use crate::generate_localpart; /// /// Device identifiers in Matrix are completely opaque character sequences. This type alias is /// provided simply for its semantic value. -pub type DeviceId = String; +pub type DeviceId = str; /// Generates a random `DeviceId`, suitable for assignment to a new device. #[cfg(feature = "rand")] #[cfg_attr(docsrs, doc(cfg(feature = "rand")))] -pub fn generate() -> DeviceId { +pub fn generate() -> Box { generate_localpart(8) } diff --git a/ruma-identifiers/src/device_key_id.rs b/ruma-identifiers/src/device_key_id.rs index f824c286..120fbace 100644 --- a/ruma-identifiers/src/device_key_id.rs +++ b/ruma-identifiers/src/device_key_id.rs @@ -1,24 +1,16 @@ //! Identifiers for device keys for end-to-end encryption. -use crate::{error::Error, key_algorithms::DeviceKeyAlgorithm, DeviceIdRef}; +use crate::{error::Error, key_algorithms::DeviceKeyAlgorithm, DeviceId}; use std::{num::NonZeroU8, str::FromStr}; /// A key algorithm and a device id, combined with a ':' #[derive(Clone, Debug)] -pub struct DeviceKeyId { - full_id: T, +pub struct DeviceKeyId { + full_id: Box, colon_idx: NonZeroU8, } -impl DeviceKeyId -where - T: AsRef, -{ - /// Creates a reference to this `DeviceKeyId`. - pub fn as_ref(&self) -> DeviceKeyId<&str> { - DeviceKeyId { full_id: self.full_id.as_ref(), colon_idx: self.colon_idx } - } - +impl DeviceKeyId { /// Returns key algorithm of the device key ID. pub fn algorithm(&self) -> DeviceKeyAlgorithm { DeviceKeyAlgorithm::from_str(&self.full_id.as_ref()[..self.colon_idx.get() as usize]) @@ -26,14 +18,14 @@ where } /// Returns device ID of the device key ID. - pub fn device_id(&self) -> DeviceIdRef<'_> { + pub fn device_id(&self) -> &DeviceId { &self.full_id.as_ref()[self.colon_idx.get() as usize + 1..] } } -fn try_from(key_id: S) -> Result, Error> +fn try_from(key_id: S) -> Result where - S: AsRef + Into, + S: AsRef + Into>, { let key_str = key_id.as_ref(); let colon_idx = @@ -56,12 +48,12 @@ mod test { use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use super::DeviceKeyId; - use crate::{device_id::DeviceId, error::Error, key_algorithms::DeviceKeyAlgorithm}; + use crate::{error::Error, key_algorithms::DeviceKeyAlgorithm}; #[test] fn convert_device_key_id() { assert_eq!( - DeviceKeyId::<&str>::try_from("ed25519:JLAFKJWSCS") + DeviceKeyId::try_from("ed25519:JLAFKJWSCS") .expect("Failed to create device key ID.") .as_ref(), "ed25519:JLAFKJWSCS" @@ -71,7 +63,7 @@ mod test { #[cfg(feature = "serde")] #[test] fn serialize_device_key_id() { - let device_key_id = DeviceKeyId::<&str>::try_from("ed25519:JLAFKJWSCS").unwrap(); + let device_key_id = DeviceKeyId::try_from("ed25519:JLAFKJWSCS").unwrap(); let serialized = to_json_value(device_key_id).unwrap(); let expected = json!("ed25519:JLAFKJWSCS"); @@ -81,7 +73,7 @@ mod test { #[cfg(feature = "serde")] #[test] fn deserialize_device_key_id() { - let deserialized: DeviceKeyId<_> = from_json_value(json!("ed25519:JLAFKJWSCS")).unwrap(); + let deserialized: DeviceKeyId = from_json_value(json!("ed25519:JLAFKJWSCS")).unwrap(); let expected = DeviceKeyId::try_from("ed25519:JLAFKJWSCS").unwrap(); assert_eq!(deserialized, expected); @@ -89,16 +81,13 @@ mod test { #[test] fn missing_key_algorithm() { - assert_eq!( - DeviceKeyId::<&str>::try_from(":JLAFKJWSCS").unwrap_err(), - Error::UnknownKeyAlgorithm - ); + assert_eq!(DeviceKeyId::try_from(":JLAFKJWSCS").unwrap_err(), Error::UnknownKeyAlgorithm); } #[test] fn missing_delimiter() { assert_eq!( - DeviceKeyId::<&str>::try_from("ed25519|JLAFKJWSCS").unwrap_err(), + DeviceKeyId::try_from("ed25519|JLAFKJWSCS").unwrap_err(), Error::MissingDeviceKeyDelimiter, ); } @@ -106,25 +95,25 @@ mod test { #[test] fn unknown_key_algorithm() { assert_eq!( - DeviceKeyId::<&str>::try_from("signed_curve25510:JLAFKJWSCS").unwrap_err(), + DeviceKeyId::try_from("signed_curve25510:JLAFKJWSCS").unwrap_err(), Error::UnknownKeyAlgorithm, ); } #[test] fn empty_device_id_ok() { - assert!(DeviceKeyId::<&str>::try_from("ed25519:").is_ok()); + assert!(DeviceKeyId::try_from("ed25519:").is_ok()); } #[test] fn valid_key_algorithm() { - let device_key_id = DeviceKeyId::<&str>::try_from("ed25519:JLAFKJWSCS").unwrap(); + let device_key_id = DeviceKeyId::try_from("ed25519:JLAFKJWSCS").unwrap(); assert_eq!(device_key_id.algorithm(), DeviceKeyAlgorithm::Ed25519); } #[test] fn valid_device_id() { - let device_key_id = DeviceKeyId::<&str>::try_from("ed25519:JLAFKJWSCS").unwrap(); - assert_eq!(device_key_id.device_id(), DeviceId::from("JLAFKJWSCS")); + let device_key_id = DeviceKeyId::try_from("ed25519:JLAFKJWSCS").unwrap(); + assert_eq!(device_key_id.device_id(), "JLAFKJWSCS"); } } diff --git a/ruma-identifiers/src/event_id.rs b/ruma-identifiers/src/event_id.rs index feffc248..8ef7836f 100644 --- a/ruma-identifiers/src/event_id.rs +++ b/ruma-identifiers/src/event_id.rs @@ -2,16 +2,13 @@ use std::{convert::TryFrom, num::NonZeroU8}; -use crate::{error::Error, parse_id, validate_id, ServerNameRef}; +use crate::{error::Error, parse_id, validate_id, ServerName}; /// A Matrix event ID. /// /// An `EventId` is generated randomly or converted from a string slice, and can be converted back /// into a string as needed. /// -/// It is discouraged to use this type directly – instead use one of the aliases (`EventId` and -/// `EventIdRef`) in the crate root. -/// /// # Room versions /// /// Matrix specifies multiple [room versions](https://matrix.org/docs/spec/#room-versions) and the @@ -40,16 +37,13 @@ use crate::{error::Error, parse_id, validate_id, ServerNameRef}; /// "$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg" /// ); /// ``` -#[derive(Clone, Copy, Debug)] -pub struct EventId { - full_id: T, +#[derive(Clone, Debug)] +pub struct EventId { + full_id: Box, colon_idx: Option, } -impl EventId -where - String: Into, -{ +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. @@ -58,7 +52,7 @@ where /// parsed as a valid host. #[cfg(feature = "rand")] #[cfg_attr(docsrs, doc(cfg(feature = "rand")))] - pub fn new(server_name: ServerNameRef<'_>) -> Self { + pub fn new(server_name: &ServerName) -> Self { use crate::generate_localpart; let full_id = format!("${}:{}", generate_localpart(18), server_name).into(); @@ -67,33 +61,25 @@ where } } -impl EventId -where - T: AsRef, -{ - /// Creates a reference to this `EventId`. - pub fn as_ref(&self) -> EventId<&str> { - EventId { full_id: self.full_id.as_ref(), colon_idx: self.colon_idx } - } - +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 { let idx = match self.colon_idx { Some(idx) => idx.get() as usize, - None => self.full_id.as_ref().len(), + None => self.full_id.len(), }; - &self.full_id.as_ref()[1..idx] + &self.full_id[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> { + pub fn server_name(&self) -> Option<&ServerName> { self.colon_idx.map(|idx| { - ServerNameRef::try_from(&self.full_id.as_ref()[idx.get() as usize + 1..]).unwrap() + <&ServerName>::try_from(&self.full_id.as_ref()[idx.get() as usize + 1..]).unwrap() }) } } @@ -102,9 +88,9 @@ where /// /// 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, Error> +fn try_from(event_id: S) -> Result where - S: AsRef + Into, + S: AsRef + Into>, { if event_id.as_ref().contains(':') { let colon_idx = parse_id(event_id.as_ref(), &['$'])?; @@ -126,9 +112,8 @@ mod tests { #[cfg(feature = "serde")] use serde_json::{from_str, to_string}; - use crate::{error::Error, ServerNameRef}; - - type EventId = super::EventId>; + use super::EventId; + use crate::{error::Error, ServerName}; #[test] fn valid_original_event_id() { @@ -164,7 +149,7 @@ mod tests { #[test] fn generate_random_valid_event_id() { let server_name = - ServerNameRef::try_from("example.com").expect("Failed to parse ServerName"); + <&ServerName>::try_from("example.com").expect("Failed to parse ServerName"); let event_id = EventId::new(server_name); let id_str = event_id.as_str(); diff --git a/ruma-identifiers/src/lib.rs b/ruma-identifiers/src/lib.rs index 48014b0d..b2d1ca02 100644 --- a/ruma-identifiers/src/lib.rs +++ b/ruma-identifiers/src/lib.rs @@ -13,152 +13,44 @@ use std::{convert::TryFrom, num::NonZeroU8}; use serde::de::{self, Deserialize as _, Deserializer, Unexpected}; #[doc(inline)] -pub use crate::error::Error; +pub use crate::{ + device_id::DeviceId, + device_key_id::DeviceKeyId, + error::Error, + event_id::EventId, + key_algorithms::{DeviceKeyAlgorithm, ServerKeyAlgorithm}, + room_alias_id::RoomAliasId, + room_id::RoomId, + room_id_or_room_alias_id::RoomIdOrAliasId, + room_version_id::RoomVersionId, + server_key_id::ServerKeyId, + server_name::ServerName, + user_id::UserId, +}; #[macro_use] mod macros; -mod error; - pub mod device_id; -pub mod device_key_id; -pub mod event_id; -pub mod key_algorithms; -pub mod room_alias_id; -pub mod room_id; -pub mod room_id_or_room_alias_id; -pub mod room_version_id; -pub mod server_key_id; -#[allow(deprecated)] -pub mod server_name; pub mod user_id; -/// Allowed algorithms for homeserver signing keys. -pub type DeviceKeyAlgorithm = key_algorithms::DeviceKeyAlgorithm; - -/// An owned device key identifier containing a key algorithm and device ID. -/// -/// Can be created via `TryFrom` and `TryFrom<&str>`; implements `Serialize` -/// and `Deserialize` if the `serde` feature is enabled. -pub type DeviceKeyId = device_key_id::DeviceKeyId>; - -/// A reference to a device key identifier containing a key algorithm and device ID. -/// -/// Can be created via `TryFrom<&str>`; implements `Serialize` and `Deserialize` -/// if the `serde` feature is enabled. -pub type DeviceKeyIdRef<'a> = device_key_id::DeviceKeyId<&'a str>; - -/// An owned device ID. -/// -/// While this is currently just a `String`, that will likely change in the future. -pub use device_id::DeviceId; - -/// A reference to a device ID. -/// -/// While this is currently just a string slice, that will likely change in the future. -pub type DeviceIdRef<'a> = &'a str; - -/// An owned event ID. -/// -/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom` + -/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled. -pub type EventId = event_id::EventId>; - -/// A reference to an event ID. -/// -/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled. -pub type EventIdRef<'a> = event_id::EventId<&'a str>; - -/// An owned room alias ID. -/// -/// Can be created via `TryFrom` and `TryFrom<&str>`, implements `Serialize` and -/// `Deserialize` if the `serde` feature is enabled. -pub type RoomAliasId = room_alias_id::RoomAliasId>; - -/// A reference to a room alias ID. -/// -/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled. -pub type RoomAliasIdRef<'a> = room_alias_id::RoomAliasId<&'a str>; - -/// An owned room ID. -/// -/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom` + -/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled. -pub type RoomId = room_id::RoomId>; - -/// A reference to a room ID. -/// -/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled. -pub type RoomIdRef<'a> = room_id::RoomId<&'a str>; - -/// An owned room alias ID or room ID. -/// -/// Can be created via `TryFrom`, `TryFrom<&str>`, `From` and `From`; -/// implements `Serialize` and `Deserialize` if the `serde` feature is enabled. -pub type RoomIdOrAliasId = room_id_or_room_alias_id::RoomIdOrAliasId>; - -/// A reference to a room alias ID or room ID. -/// -/// Can be created via `TryFrom<&str>`, `From` and `From`; implements -/// `Serialize` if the `serde` feature is enabled. -pub type RoomIdOrAliasIdRef<'a> = room_id_or_room_alias_id::RoomIdOrAliasId<&'a str>; - -/// An owned room version ID. -/// -/// Can be created using the `version_N` constructor functions, `TryFrom` and -/// `TryFrom<&str>`; implements `Serialize` and `Deserialize` if the `serde` feature is enabled. -pub type RoomVersionId = room_version_id::RoomVersionId>; - -/// A reference to a room version ID. -/// -/// Can be created using the `version_N` constructor functions and via `TryFrom<&str>`, implements -/// `Serialize` if the `serde` feature is enabled. -pub type RoomVersionIdRef<'a> = room_version_id::RoomVersionId<&'a str>; - -/// Allowed algorithms for homeserver signing keys. -pub type ServerKeyAlgorithm = key_algorithms::ServerKeyAlgorithm; - -/// An owned homeserver signing key identifier containing a key algorithm and version. -/// -/// Can be created via `TryFrom` and `TryFrom<&str>`; implements `Serialize` -/// and `Deserialize` if the `serde` feature is enabled. -pub type ServerKeyId = server_key_id::ServerKeyId>; - -/// A reference to a homeserver signing key identifier containing a key -/// algorithm and version. -/// -/// Can be created via `TryFrom<&str>`; implements `Serialize` -/// and `Deserialize` if the `serde` feature is enabled. -pub type ServerKeyIdRef<'a> = server_key_id::ServerKeyId<&'a str>; - -/// An owned homeserver IP address or hostname. -/// -/// Can be created via `TryFrom` and `TryFrom<&str>`; implements `Serialize` -/// and `Deserialize` if the `serde` feature is enabled. -pub type ServerName = server_name::ServerName>; - -/// A reference to a homeserver IP address or hostname. -/// -/// Can be created via `TryFrom<&str>`; implements `Serialize` -/// and `Deserialize` if the `serde` feature is enabled. -pub type ServerNameRef<'a> = server_name::ServerName<&'a str>; -/// An owned user ID. -/// -/// Can be created via `new` (if the `rand` feature is enabled) and `TryFrom` + -/// `TryFrom<&str>`, implements `Serialize` and `Deserialize` if the `serde` feature is enabled. -pub type UserId = user_id::UserId>; - -/// A reference to a user ID. -/// -/// Can be created via `TryFrom<&str>`, implements `Serialize` if the `serde` feature is enabled. -pub type UserIdRef<'a> = user_id::UserId<&'a str>; +mod device_key_id; +mod error; +mod event_id; +mod key_algorithms; +mod room_alias_id; +mod room_id; +mod room_id_or_room_alias_id; +mod room_version_id; +mod server_key_id; +mod server_name; /// Check whether a given string is a valid server name according to [the specification][]. /// /// [the specification]: https://matrix.org/docs/spec/appendices#server-name #[deprecated = "Use the [`ServerName`](server_name/struct.ServerName.html) type instead."] pub fn is_valid_server_name(name: &str) -> bool { - ServerNameRef::try_from(name).is_ok() + <&ServerName>::try_from(name).is_ok() } /// All identifiers must be 255 bytes or less. @@ -171,9 +63,13 @@ const MIN_CHARS: usize = 4; /// Generates a random identifier localpart. #[cfg(feature = "rand")] -fn generate_localpart(length: usize) -> String { +fn generate_localpart(length: usize) -> Box { use rand::Rng as _; - rand::thread_rng().sample_iter(&rand::distributions::Alphanumeric).take(length).collect() + rand::thread_rng() + .sample_iter(&rand::distributions::Alphanumeric) + .take(length) + .collect::() + .into_boxed_str() } /// Checks if an identifier is valid. @@ -203,7 +99,7 @@ fn parse_id(id: &str, valid_sigils: &[char]) -> Result { return Err(Error::InvalidLocalPart); } - server_name::ServerName::<&str>::try_from(&id[colon_idx + 1..])?; + server_name::validate(&id[colon_idx + 1..])?; Ok(NonZeroU8::new(colon_idx as u8).unwrap()) } diff --git a/ruma-identifiers/src/macros.rs b/ruma-identifiers/src/macros.rs index 24b8a54d..cec6aac4 100644 --- a/ruma-identifiers/src/macros.rs +++ b/ruma-identifiers/src/macros.rs @@ -6,8 +6,8 @@ macro_rules! doc_concat { } macro_rules! common_impls { - ($id:ident, $try_from:ident, $desc:literal) => { - impl> $id { + ($id:ty, $try_from:ident, $desc:literal) => { + impl $id { doc_concat! { #[doc = concat!("Creates a string slice from this `", stringify!($id), "`")] pub fn as_str(&self) -> &str { @@ -16,27 +16,19 @@ macro_rules! common_impls { } } - impl<'a> ::std::convert::From<&'a $id>> for $id<&'a str> { - fn from(id: &'a $id>) -> Self { - id.as_ref() + impl ::std::convert::AsRef for $id { + fn as_ref(&self) -> &str { + self.as_str() } } - 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<'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> { + impl ::std::convert::TryFrom<&str> for $id { type Error = crate::error::Error; fn try_from(s: &str) -> Result { @@ -44,7 +36,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 { @@ -52,56 +44,50 @@ macro_rules! common_impls { } } - impl> ::std::convert::AsRef for $id { - fn as_ref(&self) -> &str { - 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) + write!(f, "{}", self.as_str()) } } - impl ::std::cmp::PartialEq for $id { + impl ::std::cmp::PartialEq for $id { fn eq(&self, other: &Self) -> bool { - self.full_id == other.full_id + self.as_str() == other.as_str() } } - 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) + ::std::cmp::PartialOrd::partial_cmp(self.as_str(), other.as_str()) } } - 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) + ::std::cmp::Ord::cmp(self.as_str(), other.as_str()) } } - impl ::std::hash::Hash for $id { + impl ::std::hash::Hash for $id { fn hash(&self, state: &mut H) { - self.full_id.hash(state); + self.as_str().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.as_ref()) + serializer.serialize_str(self.as_str()) } } #[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>, @@ -110,27 +96,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.as_ref() == *other + self.as_str() == *other } } - impl> ::std::cmp::PartialEq<$id> for &str { - fn eq(&self, other: &$id) -> bool { - *self == other.full_id.as_ref() + impl ::std::cmp::PartialEq<$id> for &str { + fn eq(&self, other: &$id) -> bool { + *self == other.as_str() } } - 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.as_ref() == &other[..] + self.as_str() == other.as_str() } } - impl> ::std::cmp::PartialEq<$id> for ::std::string::String { - fn eq(&self, other: &$id) -> bool { - &self[..] == other.full_id.as_ref() + impl ::std::cmp::PartialEq<$id> for ::std::string::String { + fn eq(&self, other: &$id) -> bool { + self.as_str() == other.as_str() } } }; diff --git a/ruma-identifiers/src/room_alias_id.rs b/ruma-identifiers/src/room_alias_id.rs index 01000551..1242134f 100644 --- a/ruma-identifiers/src/room_alias_id.rs +++ b/ruma-identifiers/src/room_alias_id.rs @@ -6,9 +6,6 @@ use crate::{error::Error, parse_id, server_name::ServerName}; /// A Matrix room alias ID. /// -/// It is discouraged to use this type directly – instead use one of the aliases (`RoomAliasId` and -/// `RoomAliasIdRef`) in the crate root. -/// /// A `RoomAliasId` is converted from a string slice, and can be converted back into a string as /// needed. /// @@ -20,38 +17,30 @@ use crate::{error::Error, parse_id, server_name::ServerName}; /// "#ruma:example.com" /// ); /// ``` -#[derive(Clone, Copy, Debug)] -pub struct RoomAliasId { - pub(crate) full_id: T, +#[derive(Clone, Debug)] +pub struct RoomAliasId { + pub(crate) full_id: Box, pub(crate) colon_idx: NonZeroU8, } -impl RoomAliasId -where - T: AsRef, -{ - /// Creates a reference to this `RoomAliasId`. - pub fn as_ref(&self) -> RoomAliasId<&str> { - RoomAliasId { full_id: self.full_id.as_ref(), colon_idx: self.colon_idx } - } - +impl RoomAliasId { /// Returns the room's alias. pub fn alias(&self) -> &str { - &self.full_id.as_ref()[1..self.colon_idx.get() as usize] + &self.full_id[1..self.colon_idx.get() as usize] } /// Returns the server name of the room alias ID. - pub fn server_name(&self) -> ServerName<&str> { - ServerName::try_from(&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]).unwrap() + pub fn server_name(&self) -> &ServerName { + <&ServerName>::try_from(&self.full_id[self.colon_idx.get() as usize + 1..]).unwrap() } } /// 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, Error> +fn try_from(room_id: S) -> Result where - S: AsRef + Into, + S: AsRef + Into>, { let colon_idx = parse_id(room_id.as_ref(), &['#'])?; @@ -67,10 +56,9 @@ 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/ruma-identifiers/src/room_id.rs b/ruma-identifiers/src/room_id.rs index 672020a8..66f258bd 100644 --- a/ruma-identifiers/src/room_id.rs +++ b/ruma-identifiers/src/room_id.rs @@ -2,16 +2,13 @@ use std::{convert::TryFrom, num::NonZeroU8}; -use crate::{error::Error, parse_id, ServerNameRef}; +use crate::{error::Error, parse_id, ServerName}; /// A Matrix room ID. /// /// A `RoomId` is generated randomly or converted from a string slice, and can be converted back /// into a string as needed. /// -/// It is discouraged to use this type directly – instead use one of the aliases (`RoomId` and -/// `RoomIdRef`) in the crate root. -/// /// ``` /// # use std::convert::TryFrom; /// # use ruma_identifiers::RoomId; @@ -20,23 +17,20 @@ use crate::{error::Error, parse_id, ServerNameRef}; /// "!n8f893n9:example.com" /// ); /// ``` -#[derive(Clone, Copy, Debug)] -pub struct RoomId { - pub(crate) full_id: T, +#[derive(Clone, Debug)] +pub struct RoomId { + pub(crate) full_id: Box, pub(crate) colon_idx: NonZeroU8, } -impl RoomId -where - String: Into, -{ +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: ServerNameRef<'_>) -> Self { + pub fn new(server_name: &ServerName) -> Self { use crate::generate_localpart; let full_id = format!("!{}:{}", generate_localpart(18), server_name).into(); @@ -45,33 +39,24 @@ where } } -impl RoomId -where - T: AsRef, -{ - /// Creates a reference to this `RoomId`. - pub fn as_ref(&self) -> RoomId<&str> { - RoomId { full_id: self.full_id.as_ref(), colon_idx: self.colon_idx } - } - +impl RoomId { /// Returns the rooms's unique ID. pub fn localpart(&self) -> &str { - &self.full_id.as_ref()[1..self.colon_idx.get() as usize] + &self.full_id[1..self.colon_idx.get() as usize] } /// Returns the server name of the room ID. - pub fn server_name(&self) -> ServerNameRef<'_> { - ServerNameRef::try_from(&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]) - .unwrap() + pub fn server_name(&self) -> &ServerName { + <&ServerName>::try_from(&self.full_id[self.colon_idx.get() as usize + 1..]).unwrap() } } /// 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, Error> +fn try_from(room_id: S) -> Result where - S: AsRef + Into, + S: AsRef + Into>, { let colon_idx = parse_id(room_id.as_ref(), &['!'])?; @@ -87,9 +72,8 @@ mod tests { #[cfg(feature = "serde")] use serde_json::{from_str, to_string}; - use crate::{error::Error, ServerNameRef}; - - type RoomId = super::RoomId>; + use super::RoomId; + use crate::{error::Error, ServerName}; #[test] fn valid_room_id() { @@ -105,7 +89,7 @@ mod tests { #[test] fn generate_random_valid_room_id() { let server_name = - ServerNameRef::try_from("example.com").expect("Failed to parse ServerName"); + <&ServerName>::try_from("example.com").expect("Failed to parse ServerName"); let room_id = RoomId::new(server_name); let id_str = room_id.as_str(); diff --git a/ruma-identifiers/src/room_id_or_room_alias_id.rs b/ruma-identifiers/src/room_id_or_room_alias_id.rs index b9f59012..60e89bd7 100644 --- a/ruma-identifiers/src/room_id_or_room_alias_id.rs +++ b/ruma-identifiers/src/room_id_or_room_alias_id.rs @@ -2,9 +2,7 @@ use std::{convert::TryFrom, hint::unreachable_unchecked, num::NonZeroU8}; -use crate::{ - error::Error, parse_id, room_alias_id::RoomAliasId, room_id::RoomId, server_name::ServerName, -}; +use crate::{error::Error, parse_id, server_name::ServerName, RoomAliasId, RoomId}; /// A Matrix room ID or a Matrix room alias ID. /// @@ -12,9 +10,6 @@ use crate::{ /// from a string slice, and can be converted back into a string as needed. When converted from a /// string slice, the variant is determined by the leading sigil character. /// -/// It is discouraged to use this type directly – instead use one of the aliases -/// (`RoomIdOrRoomAliasId` and `RoomIdOrRoomAliasIdRef`) in the crate root. -/// /// ``` /// # use std::convert::TryFrom; /// # use ruma_identifiers::RoomIdOrAliasId; @@ -28,29 +23,21 @@ use crate::{ /// "!n8f893n9:example.com" /// ); /// ``` -#[derive(Clone, Copy, Debug)] -pub struct RoomIdOrAliasId { - full_id: T, +#[derive(Clone, Debug)] +pub struct RoomIdOrAliasId { + full_id: Box, colon_idx: NonZeroU8, } -impl RoomIdOrAliasId -where - T: AsRef, -{ - /// Creates a reference to this `RoomIdOrAliasId`. - pub fn as_ref(&self) -> RoomIdOrAliasId<&str> { - RoomIdOrAliasId { full_id: self.full_id.as_ref(), colon_idx: self.colon_idx } - } - +impl RoomIdOrAliasId { /// Returns the local part (everything after the `!` or `#` and before the first colon). pub fn localpart(&self) -> &str { - &self.full_id.as_ref()[1..self.colon_idx.get() as usize] + &self.full_id[1..self.colon_idx.get() as usize] } /// Returns the server name of the room (alias) ID. - pub fn server_name(&self) -> ServerName<&str> { - ServerName::try_from(&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]).unwrap() + pub fn server_name(&self) -> &ServerName { + <&ServerName>::try_from(&self.full_id[self.colon_idx.get() as usize + 1..]).unwrap() } /// Whether this is a room id (starts with `'!'`) @@ -66,7 +53,7 @@ where /// Turn this `RoomIdOrAliasId` into `Either` #[cfg(feature = "either")] #[cfg_attr(docsrs, doc(cfg(feature = "either")))] - pub fn into_either(self) -> either::Either, RoomAliasId> { + pub fn into_either(self) -> either::Either { match self.variant() { Variant::RoomId => { either::Either::Left(RoomId { full_id: self.full_id, colon_idx: self.colon_idx }) @@ -79,7 +66,7 @@ where } fn variant(&self) -> Variant { - match self.full_id.as_ref().bytes().next() { + match self.full_id.bytes().next() { Some(b'!') => Variant::RoomId, Some(b'#') => Variant::RoomAliasId, _ => unsafe { unreachable_unchecked() }, @@ -98,9 +85,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, Error> +fn try_from(room_id_or_alias_id: S) -> Result where - S: AsRef + Into, + S: AsRef + Into>, { let colon_idx = parse_id(room_id_or_alias_id.as_ref(), &['#', '!'])?; Ok(RoomIdOrAliasId { full_id: room_id_or_alias_id.into(), colon_idx }) @@ -108,22 +95,22 @@ where common_impls!(RoomIdOrAliasId, try_from, "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, RoomAliasId> { + fn try_from(id: RoomIdOrAliasId) -> Result { match id.variant() { Variant::RoomId => Ok(RoomId { full_id: id.full_id, colon_idx: id.colon_idx }), Variant::RoomAliasId => { @@ -133,10 +120,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, RoomId> { + fn try_from(id: RoomIdOrAliasId) -> Result { match id.variant() { Variant::RoomAliasId => { Ok(RoomAliasId { full_id: id.full_id, colon_idx: id.colon_idx }) @@ -153,10 +140,9 @@ 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/ruma-identifiers/src/room_version_id.rs b/ruma-identifiers/src/room_version_id.rs index cdd2ef69..6b5e82ea 100644 --- a/ruma-identifiers/src/room_version_id.rs +++ b/ruma-identifiers/src/room_version_id.rs @@ -19,21 +19,18 @@ const MAX_CODE_POINTS: usize = 32; /// A `RoomVersionId` can be or converted or deserialized from a string slice, and can be converted /// or serialized back into a string as needed. /// -/// It is discouraged to use this type directly – instead use one of the aliases (`RoomVersionId` -/// and `RoomVersionIdRef`) in the crate root. -/// /// ``` /// # use std::convert::TryFrom; /// # use ruma_identifiers::RoomVersionId; /// assert_eq!(RoomVersionId::try_from("1").unwrap().as_ref(), "1"); /// ``` -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct RoomVersionId(InnerRoomVersionId); +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct RoomVersionId(InnerRoomVersionId); /// Possibile values for room version, distinguishing between official Matrix versions and custom /// versions. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum InnerRoomVersionId { +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum InnerRoomVersionId { /// A version 1 room. Version1, @@ -53,10 +50,10 @@ enum InnerRoomVersionId { Version6, /// A custom room version. - Custom(T), + Custom(Box), } -impl RoomVersionId { +impl RoomVersionId { /// Creates a version 1 room ID. pub fn version_1() -> Self { Self(InnerRoomVersionId::Version1) @@ -102,37 +99,37 @@ impl RoomVersionId { /// Whether or not this is a version 1 room. pub fn is_version_1(&self) -> bool { - matches!(self.0, InnerRoomVersionId::Version1) + self.0 == InnerRoomVersionId::Version1 } /// Whether or not this is a version 2 room. pub fn is_version_2(&self) -> bool { - matches!(self.0, InnerRoomVersionId::Version2) + self.0 == InnerRoomVersionId::Version2 } /// Whether or not this is a version 3 room. pub fn is_version_3(&self) -> bool { - matches!(self.0, InnerRoomVersionId::Version3) + self.0 == InnerRoomVersionId::Version3 } /// Whether or not this is a version 4 room. pub fn is_version_4(&self) -> bool { - matches!(self.0, InnerRoomVersionId::Version4) + self.0 == InnerRoomVersionId::Version4 } /// Whether or not this is a version 5 room. pub fn is_version_5(&self) -> bool { - matches!(self.0, InnerRoomVersionId::Version5) + self.0 == InnerRoomVersionId::Version5 } /// Whether or not this is a version 6 room. pub fn is_version_6(&self) -> bool { - matches!(self.0, InnerRoomVersionId::Version5) + 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(), @@ -145,7 +142,7 @@ impl From>> for String { } } -impl> AsRef for RoomVersionId { +impl AsRef for RoomVersionId { fn as_ref(&self) -> &str { match &self.0 { InnerRoomVersionId::Version1 => "1", @@ -154,31 +151,31 @@ impl> AsRef for RoomVersionId { InnerRoomVersionId::Version4 => "4", InnerRoomVersionId::Version5 => "5", InnerRoomVersionId::Version6 => "6", - InnerRoomVersionId::Custom(version) => version.as_ref(), + InnerRoomVersionId::Custom(version) => version, } } } -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, @@ -188,7 +185,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>, @@ -198,9 +195,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, Error> +fn try_from(room_version_id: S) -> Result where - S: AsRef + Into, + S: AsRef + Into>, { let version = match room_version_id.as_ref() { "1" => RoomVersionId(InnerRoomVersionId::Version1), @@ -222,15 +219,7 @@ where Ok(version) } -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> { +impl TryFrom<&str> for RoomVersionId { type Error = crate::error::Error; fn try_from(s: &str) -> Result { @@ -238,7 +227,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 { @@ -246,26 +235,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() } } @@ -277,10 +266,9 @@ 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/ruma-identifiers/src/server_key_id.rs b/ruma-identifiers/src/server_key_id.rs index 57318557..84da5a19 100644 --- a/ruma-identifiers/src/server_key_id.rs +++ b/ruma-identifiers/src/server_key_id.rs @@ -6,20 +6,12 @@ use crate::{error::Error, key_algorithms::ServerKeyAlgorithm}; /// Key identifiers used for homeserver signing keys. #[derive(Clone, Debug)] -pub struct ServerKeyId { - full_id: T, +pub struct ServerKeyId { + full_id: Box, colon_idx: NonZeroU8, } -impl ServerKeyId -where - T: AsRef, -{ - /// Creates a reference to this `ServerKeyId`. - pub fn as_ref(&self) -> ServerKeyId<&str> { - ServerKeyId { full_id: self.full_id.as_ref(), colon_idx: self.colon_idx } - } - +impl ServerKeyId { /// Returns key algorithm of the server key ID. pub fn algorithm(&self) -> ServerKeyAlgorithm { ServerKeyAlgorithm::from_str(&self.full_id.as_ref()[..self.colon_idx.get() as usize]) @@ -32,9 +24,9 @@ where } } -fn try_from(key_id: S) -> Result, Error> +fn try_from(key_id: S) -> Result where - S: AsRef + Into, + S: AsRef + Into>, { let key_str = key_id.as_ref(); let colon_idx = @@ -83,7 +75,7 @@ mod tests { #[cfg(feature = "serde")] #[test] fn deserialize_id() { - let server_key_id: ServerKeyId<_> = from_json_value(json!("ed25519:Abc_1")).unwrap(); + let server_key_id: ServerKeyId = from_json_value(json!("ed25519:Abc_1")).unwrap(); assert_eq!(server_key_id.algorithm(), ServerKeyAlgorithm::Ed25519); assert_eq!(server_key_id.version(), "Abc_1"); } @@ -91,22 +83,19 @@ mod tests { #[cfg(feature = "serde")] #[test] fn serialize_id() { - let server_key_id: ServerKeyId<&str> = ServerKeyId::try_from("ed25519:abc123").unwrap(); + let server_key_id: ServerKeyId = ServerKeyId::try_from("ed25519:abc123").unwrap(); assert_eq!(to_json_value(&server_key_id).unwrap(), json!("ed25519:abc123")); } #[test] fn invalid_version_characters() { - assert_eq!( - ServerKeyId::<&str>::try_from("ed25519:Abc-1").unwrap_err(), - Error::InvalidCharacters, - ); + assert_eq!(ServerKeyId::try_from("ed25519:Abc-1").unwrap_err(), Error::InvalidCharacters,); } #[test] fn invalid_key_algorithm() { assert_eq!( - ServerKeyId::<&str>::try_from("signed_curve25519:Abc-1").unwrap_err(), + ServerKeyId::try_from("signed_curve25519:Abc-1").unwrap_err(), Error::UnknownKeyAlgorithm, ); } @@ -114,7 +103,7 @@ mod tests { #[test] fn missing_delimiter() { assert_eq!( - ServerKeyId::<&str>::try_from("ed25519|Abc_1").unwrap_err(), + ServerKeyId::try_from("ed25519|Abc_1").unwrap_err(), Error::MissingServerKeyDelimiter, ); } diff --git a/ruma-identifiers/src/server_name.rs b/ruma-identifiers/src/server_name.rs index c28324a5..c83dd759 100644 --- a/ruma-identifiers/src/server_name.rs +++ b/ruma-identifiers/src/server_name.rs @@ -1,53 +1,75 @@ //! Matrix-spec compliant server names. +use std::{ + convert::TryFrom, + fmt::{self, Display}, + mem, +}; + use crate::error::Error; /// A Matrix-spec compliant server name. -/// -/// It is discouraged to use this type directly – instead use one of the aliases ([`ServerName`](../type.ServerName.html) and -/// [`ServerNameRef`](../type.ServerNameRef.html)) in the crate root. -#[derive(Clone, Copy, Debug)] -pub struct ServerName { - full_id: T, -} +#[repr(transparent)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(transparent))] +pub struct ServerName(str); -impl ServerName -where - T: AsRef, -{ - /// Creates a reference to this `ServerName`. - pub fn as_ref(&self) -> ServerName<&str> { - ServerName { full_id: self.full_id.as_ref() } +impl ServerName { + #[allow(clippy::transmute_ptr_to_ptr)] + fn from_borrowed(s: &str) -> &Self { + unsafe { mem::transmute(s) } + } + + fn from_owned(s: Box) -> Box { + unsafe { mem::transmute(s) } + } + + fn into_owned(self: Box) -> Box { + unsafe { mem::transmute(self) } + } + + /// Creates a string slice from this `ServerName`. + pub fn as_str(&self) -> &str { + &self.0 } } -fn try_from(server_name: S) -> Result, Error> -where - S: AsRef + Into, -{ +impl Clone for Box { + fn clone(&self) -> Self { + (**self).to_owned() + } +} + +impl ToOwned for ServerName { + type Owned = Box; + + fn to_owned(&self) -> Self::Owned { + Self::from_owned(self.0.to_owned().into_boxed_str()) + } +} + +pub(crate) fn validate(server_name: &str) -> Result<(), Error> { use std::net::Ipv6Addr; - let name = server_name.as_ref(); - - if name.is_empty() { + if server_name.is_empty() { return Err(Error::InvalidServerName); } - let end_of_host = if name.starts_with('[') { - let end_of_ipv6 = match name.find(']') { + let end_of_host = if server_name.starts_with('[') { + let end_of_ipv6 = match server_name.find(']') { Some(idx) => idx, None => return Err(Error::InvalidServerName), }; - if name[1..end_of_ipv6].parse::().is_err() { + if server_name[1..end_of_ipv6].parse::().is_err() { return Err(Error::InvalidServerName); } end_of_ipv6 + 1 } else { - let end_of_host = name.find(':').unwrap_or_else(|| name.len()); + let end_of_host = server_name.find(':').unwrap_or_else(|| server_name.len()); - if name[..end_of_host] + if server_name[..end_of_host] .bytes() .any(|byte| !(byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'.')) { @@ -57,81 +79,170 @@ where end_of_host }; - if name.len() != end_of_host + if server_name.len() != end_of_host && ( // hostname is followed by something other than ":port" - name.as_bytes()[end_of_host] != b':' + server_name.as_bytes()[end_of_host] != b':' // the remaining characters after ':' are not a valid port - || name[end_of_host + 1..].parse::().is_err() + || server_name[end_of_host + 1..].parse::().is_err() ) { Err(Error::InvalidServerName) } else { - Ok(ServerName { full_id: server_name.into() }) + Ok(()) } } -common_impls!(ServerName, try_from, "An IP address or hostname"); +fn try_from(server_name: S) -> Result, Error> +where + S: AsRef + Into>, +{ + validate(server_name.as_ref())?; + Ok(ServerName::from_owned(server_name.into())) +} + +impl AsRef for ServerName { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl AsRef for Box { + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl From> for String { + fn from(id: Box) -> Self { + id.into_owned().into() + } +} + +impl<'a> TryFrom<&'a str> for &'a ServerName { + type Error = Error; + + fn try_from(server_name: &'a str) -> Result { + validate(server_name)?; + Ok(ServerName::from_borrowed(server_name)) + } +} + +impl TryFrom<&str> for Box { + type Error = crate::error::Error; + + fn try_from(s: &str) -> Result { + try_from(s) + } +} + +impl TryFrom for Box { + type Error = crate::error::Error; + + fn try_from(s: String) -> Result { + try_from(s) + } +} + +impl Display for ServerName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Box { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + crate::deserialize_id(deserializer, "An IP address or hostname") + } +} + +impl PartialEq for ServerName { + fn eq(&self, other: &str) -> bool { + self.as_str() == other + } +} + +impl PartialEq for str { + fn eq(&self, other: &ServerName) -> bool { + self == other.as_str() + } +} + +impl PartialEq for ServerName { + fn eq(&self, other: &String) -> bool { + self.as_str() == other.as_str() + } +} + +impl PartialEq for String { + fn eq(&self, other: &ServerName) -> bool { + self.as_str() == other.as_str() + } +} #[cfg(test)] mod tests { use std::convert::TryFrom; - use crate::ServerNameRef; + use super::ServerName; #[test] fn ipv4_host() { - assert!(ServerNameRef::try_from("127.0.0.1").is_ok()); + assert!(<&ServerName>::try_from("127.0.0.1").is_ok()); } #[test] fn ipv4_host_and_port() { - assert!(ServerNameRef::try_from("1.1.1.1:12000").is_ok()); + assert!(<&ServerName>::try_from("1.1.1.1:12000").is_ok()); } #[test] fn ipv6() { - assert!(ServerNameRef::try_from("[::1]").is_ok()); + assert!(<&ServerName>::try_from("[::1]").is_ok()); } #[test] fn ipv6_with_port() { - assert!(ServerNameRef::try_from("[1234:5678::abcd]:5678").is_ok()); + assert!(<&ServerName>::try_from("[1234:5678::abcd]:5678").is_ok()); } #[test] fn dns_name() { - assert!(ServerNameRef::try_from("example.com").is_ok()); + assert!(<&ServerName>::try_from("example.com").is_ok()); } #[test] fn dns_name_with_port() { - assert!(ServerNameRef::try_from("ruma.io:8080").is_ok()); + assert!(<&ServerName>::try_from("ruma.io:8080").is_ok()); } #[test] fn empty_string() { - assert!(ServerNameRef::try_from("").is_err()); + assert!(<&ServerName>::try_from("").is_err()); } #[test] fn invalid_ipv6() { - assert!(ServerNameRef::try_from("[test::1]").is_err()); + assert!(<&ServerName>::try_from("[test::1]").is_err()); } #[test] fn ipv4_with_invalid_port() { - assert!(ServerNameRef::try_from("127.0.0.1:").is_err()); + assert!(<&ServerName>::try_from("127.0.0.1:").is_err()); } #[test] fn ipv6_with_invalid_port() { - assert!(ServerNameRef::try_from("[fe80::1]:100000").is_err()); - assert!(ServerNameRef::try_from("[fe80::1]!").is_err()); + assert!(<&ServerName>::try_from("[fe80::1]:100000").is_err()); + assert!(<&ServerName>::try_from("[fe80::1]!").is_err()); } #[test] fn dns_name_with_invalid_port() { - assert!(ServerNameRef::try_from("matrix.org:hello").is_err()); + assert!(<&ServerName>::try_from("matrix.org:hello").is_err()); } } diff --git a/ruma-identifiers/src/user_id.rs b/ruma-identifiers/src/user_id.rs index 63f3c5cc..26ec27f1 100644 --- a/ruma-identifiers/src/user_id.rs +++ b/ruma-identifiers/src/user_id.rs @@ -2,16 +2,13 @@ use std::{convert::TryFrom, num::NonZeroU8}; -use crate::{error::Error, parse_id, ServerNameRef}; +use crate::{error::Error, parse_id, ServerName}; /// A Matrix user ID. /// /// A `UserId` is generated randomly or converted from a string slice, and can be converted back /// into a string as needed. /// -/// It is discouraged to use this type directly – instead use one of the aliases (`UserId` and -/// `UserIdRef`) in the crate root. -/// /// ``` /// # use std::convert::TryFrom; /// # use ruma_identifiers::UserId; @@ -20,9 +17,9 @@ use crate::{error::Error, parse_id, ServerNameRef}; /// "@carl:example.com" /// ); /// ``` -#[derive(Clone, Copy, Debug)] -pub struct UserId { - full_id: T, +#[derive(Clone, Debug)] +pub struct UserId { + full_id: Box, colon_idx: NonZeroU8, /// Whether this user id is a historical one. /// @@ -32,15 +29,12 @@ pub struct UserId { is_historical: bool, } -impl UserId -where - String: Into, -{ +impl UserId { /// Attempts to generate a `UserId` for the given origin server with a localpart consisting of /// 12 random ASCII characters. #[cfg(feature = "rand")] #[cfg_attr(docsrs, doc(cfg(feature = "rand")))] - pub fn new(server_name: ServerNameRef<'_>) -> Self { + pub fn new(server_name: &ServerName) -> Self { use crate::generate_localpart; let full_id = format!("@{}:{}", generate_localpart(12).to_lowercase(), server_name).into(); @@ -56,13 +50,13 @@ where /// 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, - server_name: ServerNameRef<'_>, + id: impl AsRef + Into>, + server_name: &ServerName, ) -> Result { let id_str = id.as_ref(); if id_str.starts_with('@') { - try_from(id) + try_from(id.into()) } else { let is_fully_conforming = localpart_is_fully_comforming(id_str)?; @@ -75,32 +69,18 @@ where } } -impl UserId -where - T: AsRef, -{ - /// Creates a reference to this `UserId`. - pub fn as_ref(&self) -> UserId<&str> { - UserId { - full_id: self.full_id.as_ref(), - colon_idx: self.colon_idx, - is_historical: self.is_historical, - } - } - +impl UserId { /// Returns the user's localpart. pub fn localpart(&self) -> &str { - &self.full_id.as_ref()[1..self.colon_idx.get() as usize] + &self.full_id[1..self.colon_idx.get() as usize] } /// Returns the server name of the user ID. - pub fn server_name(&self) -> ServerNameRef<'_> { - ServerNameRef::try_from(&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]) + pub fn server_name(&self) -> &ServerName { + <&ServerName>::try_from(&self.full_id.as_ref()[self.colon_idx.get() as usize + 1..]) .unwrap() } -} -impl UserId { /// Whether this user ID is a historical one, i.e. one that doesn't conform to the latest /// specification of the user ID grammar but is still accepted because it was previously /// allowed. @@ -112,9 +92,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, Error> +fn try_from(user_id: S) -> Result 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]; @@ -158,9 +138,8 @@ mod tests { #[cfg(feature = "serde")] use serde_json::{from_str, to_string}; - use crate::{error::Error, ServerNameRef}; - - type UserId = super::UserId>; + use super::UserId; + use crate::{error::Error, ServerName}; #[test] fn valid_user_id_from_str() { @@ -173,7 +152,7 @@ mod tests { #[test] fn parse_valid_user_id() { - let server_name = ServerNameRef::try_from("example.com").unwrap(); + let server_name = <&ServerName>::try_from("example.com").unwrap(); let user_id = UserId::parse_with_server_name("@carl:example.com", server_name) .expect("Failed to create UserId."); assert_eq!(user_id.as_ref(), "@carl:example.com"); @@ -184,7 +163,7 @@ mod tests { #[test] fn parse_valid_user_id_parts() { - let server_name = ServerNameRef::try_from("example.com").unwrap(); + let server_name = <&ServerName>::try_from("example.com").unwrap(); let user_id = UserId::parse_with_server_name("carl", server_name).expect("Failed to create UserId."); assert_eq!(user_id.as_ref(), "@carl:example.com"); @@ -204,7 +183,7 @@ mod tests { #[test] fn parse_valid_historical_user_id() { - let server_name = ServerNameRef::try_from("example.com").unwrap(); + let server_name = <&ServerName>::try_from("example.com").unwrap(); let user_id = UserId::parse_with_server_name("@a%b[irc]:example.com", server_name) .expect("Failed to create UserId."); assert_eq!(user_id.as_ref(), "@a%b[irc]:example.com"); @@ -215,7 +194,7 @@ mod tests { #[test] fn parse_valid_historical_user_id_parts() { - let server_name = ServerNameRef::try_from("example.com").unwrap(); + let server_name = <&ServerName>::try_from("example.com").unwrap(); let user_id = UserId::parse_with_server_name("a%b[irc]", server_name) .expect("Failed to create UserId."); assert_eq!(user_id.as_ref(), "@a%b[irc]:example.com"); @@ -234,7 +213,7 @@ mod tests { #[cfg(feature = "rand")] #[test] fn generate_random_valid_user_id() { - let server_name = ServerNameRef::try_from("example.com").unwrap(); + let server_name = <&ServerName>::try_from("example.com").unwrap(); let user_id = UserId::new(server_name); assert_eq!(user_id.localpart().len(), 12); assert_eq!(user_id.server_name(), "example.com");