identifiers: Provide Owned types

This commit is contained in:
Jonathan de Jong 2022-03-31 23:23:02 +02:00 committed by GitHub
parent a4aa7e0912
commit b77fee8948
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 250 additions and 36 deletions

View File

@ -25,6 +25,12 @@ jobs:
- name: Check Ruma - name: Check Ruma
cmd: msrv-ruma cmd: msrv-ruma
- name: Check Owned IDs with Box
cmd: msrv-owned-id-box
- name: Check Owned IDs with Arc
cmd: msrv-owned-id-arc
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@v2 uses: actions/checkout@v2
@ -33,7 +39,7 @@ jobs:
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: '1.55' toolchain: "1.55"
# Used to compile xtask # Used to compile xtask
- name: Install rust stable toolchain - name: Install rust stable toolchain

View File

@ -10,25 +10,25 @@ use serde::de::{self, Deserializer, Unexpected};
#[doc(inline)] #[doc(inline)]
pub use self::{ pub use self::{
client_secret::ClientSecret, client_secret::{ClientSecret, OwnedClientSecret},
crypto_algorithms::{DeviceKeyAlgorithm, EventEncryptionAlgorithm, SigningKeyAlgorithm}, crypto_algorithms::{DeviceKeyAlgorithm, EventEncryptionAlgorithm, SigningKeyAlgorithm},
device_id::DeviceId, device_id::{DeviceId, OwnedDeviceId},
device_key_id::DeviceKeyId, device_key_id::{DeviceKeyId, OwnedDeviceKeyId},
event_id::EventId, event_id::{EventId, OwnedEventId},
key_id::{DeviceSigningKeyId, KeyId, ServerSigningKeyId, SigningKeyId}, key_id::{DeviceSigningKeyId, KeyId, ServerSigningKeyId, SigningKeyId},
key_name::KeyName, key_name::{KeyName, OwnedKeyName},
matrix_uri::{MatrixToUri, MatrixUri}, matrix_uri::{MatrixToUri, MatrixUri},
mxc_uri::MxcUri, mxc_uri::{MxcUri, OwnedMxcUri},
room_alias_id::RoomAliasId, room_alias_id::{OwnedRoomAliasId, RoomAliasId},
room_id::RoomId, room_id::{OwnedRoomId, RoomId},
room_name::RoomName, room_name::{OwnedRoomName, RoomName},
room_or_room_alias_id::RoomOrAliasId, room_or_room_alias_id::{OwnedRoomOrAliasId, RoomOrAliasId},
room_version_id::RoomVersionId, room_version_id::RoomVersionId,
server_name::ServerName, server_name::{OwnedServerName, ServerName},
session_id::SessionId, session_id::{OwnedSessionId, SessionId},
signatures::{DeviceSignatures, EntitySignatures, ServerSignatures, Signatures}, signatures::{DeviceSignatures, EntitySignatures, ServerSignatures, Signatures},
transaction_id::TransactionId, transaction_id::{OwnedTransactionId, TransactionId},
user_id::UserId, user_id::{OwnedUserId, UserId},
}; };
#[doc(inline)] #[doc(inline)]
pub use ruma_identifiers_validation::error::Error as IdParseError; pub use ruma_identifiers_validation::error::Error as IdParseError;

View File

@ -24,7 +24,13 @@ impl ClientSecret {
} }
} }
opaque_identifier_validated!(ClientSecret, ruma_identifiers_validation::client_secret::validate); owned_identifier!(OwnedClientSecret, ClientSecret);
opaque_identifier_validated!(
ClientSecret,
OwnedClientSecret,
ruma_identifiers_validation::client_secret::validate
);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -29,7 +29,9 @@ use super::generate_localpart;
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId(str); pub struct DeviceId(str);
opaque_identifier!(DeviceId); owned_identifier!(OwnedDeviceId, DeviceId);
opaque_identifier!(DeviceId, OwnedDeviceId);
impl DeviceId { impl DeviceId {
/// Generates a random `DeviceId`, suitable for assignment to a new device. /// Generates a random `DeviceId`, suitable for assignment to a new device.

View File

@ -7,7 +7,13 @@ use super::{crypto_algorithms::DeviceKeyAlgorithm, DeviceId};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceKeyId(str); pub struct DeviceKeyId(str);
opaque_identifier_validated!(DeviceKeyId, ruma_identifiers_validation::device_key_id::validate); owned_identifier!(OwnedDeviceKeyId, DeviceKeyId);
opaque_identifier_validated!(
DeviceKeyId,
OwnedDeviceKeyId,
ruma_identifiers_validation::device_key_id::validate
);
impl DeviceKeyId { impl DeviceKeyId {
/// Create a `DeviceKeyId` from a `DeviceKeyAlgorithm` and a `DeviceId`. /// Create a `DeviceKeyId` from a `DeviceKeyAlgorithm` and a `DeviceId`.

View File

@ -38,7 +38,13 @@ use super::ServerName;
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EventId(str); pub struct EventId(str);
opaque_identifier_validated!(EventId, ruma_identifiers_validation::event_id::validate); owned_identifier!(OwnedEventId, EventId);
opaque_identifier_validated!(
EventId,
OwnedEventId,
ruma_identifiers_validation::event_id::validate
);
impl EventId { impl EventId {
/// Attempts to generate an `EventId` for the given origin server with a localpart consisting /// Attempts to generate an `EventId` for the given origin server with a localpart consisting

View File

@ -6,4 +6,6 @@
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KeyName(str); pub struct KeyName(str);
opaque_identifier!(KeyName); owned_identifier!(OwnedKeyName, KeyName);
opaque_identifier!(KeyName, OwnedKeyName);

View File

@ -24,8 +24,100 @@ macro_rules! partial_eq_string {
} }
} }
macro_rules! owned_identifier {
($owned:ident, $id:ident) => {
#[doc = concat!("Owned variant of ", stringify!($id))]
///
/// The wrapper type for this type is variable, by default it'll use [`Box`],
/// but you can change that by setting "`--cfg=ruma_identifiers_storage=...`" using
/// `RUSTFLAGS` or `.cargo/config.toml` (under `[build]` -> `rustflags = ["..."]`)
/// to the following;
/// - `ruma_identifiers_storage="Arc"` to use [`Arc`](std::sync::Arc) as a wrapper type.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $owned {
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
inner: Box<$id>,
#[cfg(ruma_identifiers_storage = "Arc")]
inner: std::sync::Arc<$id>,
}
impl AsRef<$id> for $owned {
fn as_ref(&self) -> &$id {
&*self.inner
}
}
impl AsRef<str> for $owned {
fn as_ref(&self) -> &str {
(*self.inner).as_ref()
}
}
impl std::ops::Deref for $owned {
type Target = $id;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl std::borrow::Borrow<$id> for $owned {
fn borrow(&self) -> &$id {
self.as_ref()
}
}
impl From<&'_ $id> for $owned {
fn from(id: &$id) -> $owned {
$owned { inner: id.into() }
}
}
impl From<Box<$id>> for $owned {
fn from(b: Box<$id>) -> $owned {
Self { inner: b.into() }
}
}
impl From<std::sync::Arc<$id>> for $owned {
fn from(a: std::sync::Arc<$id>) -> $owned {
Self {
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
inner: a.as_ref().into(),
#[cfg(ruma_identifiers_storage = "Arc")]
inner: a,
}
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for $owned {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_ref().as_str())
}
}
partial_eq_string!($owned);
impl PartialEq<Box<$id>> for $owned {
fn eq(&self, other: &Box<$id>) -> bool {
AsRef::<$id>::as_ref(self) == AsRef::<$id>::as_ref(other)
}
}
impl PartialEq<$owned> for Box<$id> {
fn eq(&self, other: &$owned) -> bool {
AsRef::<$id>::as_ref(self) == AsRef::<$id>::as_ref(other)
}
}
};
}
macro_rules! opaque_identifier_common_impls { macro_rules! opaque_identifier_common_impls {
($id:ty) => { ($id:ident, $owned:ident) => {
impl $id { impl $id {
pub(super) fn from_borrowed(s: &str) -> &Self { pub(super) fn from_borrowed(s: &str) -> &Self {
unsafe { std::mem::transmute(s) } unsafe { std::mem::transmute(s) }
@ -64,10 +156,20 @@ macro_rules! opaque_identifier_common_impls {
impl Clone for Box<$id> { impl Clone for Box<$id> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
(**self).to_owned() (**self).into()
} }
} }
// impl ToOwned for $id {
// type Owned = $owned;
// fn to_owned(&self) -> Self::Owned {
// Self::from_owned(self.0.into()).into()
// }
// }
// TODO swap below with above after codebase has been converted
// to not use `to_owned` as equivalent to "into Box"
impl ToOwned for $id { impl ToOwned for $id {
type Owned = Box<$id>; type Owned = Box<$id>;
@ -90,7 +192,7 @@ macro_rules! opaque_identifier_common_impls {
impl From<&$id> for Box<$id> { impl From<&$id> for Box<$id> {
fn from(id: &$id) -> Self { fn from(id: &$id) -> Self {
id.to_owned() $id::from_owned(id.0.into())
} }
} }
@ -154,13 +256,13 @@ macro_rules! opaque_identifier_common_impls {
} }
partial_eq_string!($id); partial_eq_string!($id);
partial_eq_string!(Box<$id>); partial_eq_string!(Box<$id>); // todo: Remove when all instances of Box have been converted to Owned
}; };
} }
macro_rules! opaque_identifier { macro_rules! opaque_identifier {
($id:ident) => { ($id:ident, $owned:ident) => {
opaque_identifier_common_impls!($id); opaque_identifier_common_impls!($id, $owned);
impl<'a> From<&'a str> for &'a $id { impl<'a> From<&'a str> for &'a $id {
fn from(s: &'a str) -> Self { fn from(s: &'a str) -> Self {
@ -206,11 +308,21 @@ macro_rules! opaque_identifier {
Box::<str>::deserialize(deserializer).map($id::from_owned) Box::<str>::deserialize(deserializer).map($id::from_owned)
} }
} }
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for $owned {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Box::<str>::deserialize(deserializer).map($id::from_owned).map(Into::into)
}
}
}; };
} }
macro_rules! opaque_identifier_validated { macro_rules! opaque_identifier_validated {
($id:ident, $validate_id:expr) => { ($id:ident, $owned:ident, $validate_id:expr) => {
impl $id { impl $id {
#[rustfmt::skip] #[rustfmt::skip]
doc_concat! { doc_concat! {
@ -249,7 +361,7 @@ macro_rules! opaque_identifier_validated {
} }
} }
opaque_identifier_common_impls!($id); opaque_identifier_common_impls!($id, $owned);
impl From<Box<$id>> for String { impl From<Box<$id>> for String {
fn from(id: Box<$id>) -> Self { fn from(id: Box<$id>) -> Self {
@ -273,6 +385,23 @@ macro_rules! opaque_identifier_validated {
} }
} }
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for $owned {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
let s = String::deserialize(deserializer)?;
match $id::parse(s) {
Ok(o) => Ok(o.into()),
Err(e) => Err(D::Error::custom(e)),
}
}
}
impl<'a> std::convert::TryFrom<&'a str> for &'a $id { impl<'a> std::convert::TryFrom<&'a str> for &'a $id {
type Error = crate::IdParseError; type Error = crate::IdParseError;

View File

@ -18,7 +18,9 @@ type Result<T, E = MxcUriError> = std::result::Result<T, E>;
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MxcUri(str); pub struct MxcUri(str);
opaque_identifier!(MxcUri); owned_identifier!(OwnedMxcUri, MxcUri);
opaque_identifier!(MxcUri, OwnedMxcUri);
impl MxcUri { impl MxcUri {
/// If this is a valid MXC URI, returns the media ID. /// If this is a valid MXC URI, returns the media ID.

View File

@ -18,7 +18,13 @@ use super::{matrix_uri::UriAction, server_name::ServerName, EventId, MatrixToUri
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RoomAliasId(str); pub struct RoomAliasId(str);
opaque_identifier_validated!(RoomAliasId, ruma_identifiers_validation::room_alias_id::validate); owned_identifier!(OwnedRoomAliasId, RoomAliasId);
opaque_identifier_validated!(
RoomAliasId,
OwnedRoomAliasId,
ruma_identifiers_validation::room_alias_id::validate
);
impl RoomAliasId { impl RoomAliasId {
/// Returns the room's alias. /// Returns the room's alias.

View File

@ -18,7 +18,9 @@ use super::{matrix_uri::UriAction, EventId, MatrixToUri, MatrixUri, ServerName};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RoomId(str); pub struct RoomId(str);
opaque_identifier_validated!(RoomId, ruma_identifiers_validation::room_id::validate); owned_identifier!(OwnedRoomId, RoomId);
opaque_identifier_validated!(RoomId, OwnedRoomId, ruma_identifiers_validation::room_id::validate);
impl RoomId { impl RoomId {
/// Attempts to generate a `RoomId` for the given origin server with a localpart consisting of /// Attempts to generate a `RoomId` for the given origin server with a localpart consisting of

View File

@ -7,4 +7,10 @@
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RoomName(str); pub struct RoomName(str);
opaque_identifier_validated!(RoomName, ruma_identifiers_validation::room_name::validate); owned_identifier!(OwnedRoomName, RoomName);
opaque_identifier_validated!(
RoomName,
OwnedRoomName,
ruma_identifiers_validation::room_name::validate
);

View File

@ -27,8 +27,11 @@ use super::{server_name::ServerName, RoomAliasId, RoomId};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RoomOrAliasId(str); pub struct RoomOrAliasId(str);
owned_identifier!(OwnedRoomOrAliasId, RoomOrAliasId);
opaque_identifier_validated!( opaque_identifier_validated!(
RoomOrAliasId, RoomOrAliasId,
OwnedRoomOrAliasId,
ruma_identifiers_validation::room_id_or_alias_id::validate ruma_identifiers_validation::room_id_or_alias_id::validate
); );

View File

@ -11,7 +11,13 @@ use std::net::Ipv4Addr;
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ServerName(str); pub struct ServerName(str);
opaque_identifier_validated!(ServerName, ruma_identifiers_validation::server_name::validate); owned_identifier!(OwnedServerName, ServerName);
opaque_identifier_validated!(
ServerName,
OwnedServerName,
ruma_identifiers_validation::server_name::validate
);
impl ServerName { impl ServerName {
/// Returns the host of the server name. /// Returns the host of the server name.

View File

@ -8,4 +8,10 @@
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SessionId(str); pub struct SessionId(str);
opaque_identifier_validated!(SessionId, ruma_identifiers_validation::session_id::validate); owned_identifier!(OwnedSessionId, SessionId);
opaque_identifier_validated!(
SessionId,
OwnedSessionId,
ruma_identifiers_validation::session_id::validate
);

View File

@ -22,4 +22,6 @@ impl TransactionId {
} }
} }
opaque_identifier!(TransactionId); owned_identifier!(OwnedTransactionId, TransactionId);
opaque_identifier!(TransactionId, OwnedTransactionId);

View File

@ -20,7 +20,9 @@ use super::{matrix_uri::UriAction, IdParseError, MatrixToUri, MatrixUri, ServerN
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UserId(str); pub struct UserId(str);
opaque_identifier_validated!(UserId, ruma_identifiers_validation::user_id::validate); owned_identifier!(OwnedUserId, UserId);
opaque_identifier_validated!(UserId, OwnedUserId, ruma_identifiers_validation::user_id::validate);
impl UserId { impl UserId {
/// Attempts to generate a `UserId` for the given origin server with a localpart consisting of /// Attempts to generate a `UserId` for the given origin server with a localpart consisting of

View File

@ -28,6 +28,10 @@ pub enum CiCmd {
MsrvClient, MsrvClient,
/// Check ruma crate with default features (msrv) /// Check ruma crate with default features (msrv)
MsrvRuma, MsrvRuma,
/// Check ruma-identifiers with `ruma_identifiers_storage="Box"`
MsrvOwnedIdBox,
/// Check ruma-identifiers with `ruma_identifiers_storage="Arc"`
MsrvOwnedIdArc,
/// Run all the tasks that use the stable version /// Run all the tasks that use the stable version
Stable, Stable,
/// Check all crates with all features (stable) /// Check all crates with all features (stable)
@ -85,6 +89,8 @@ impl CiTask {
Some(CiCmd::MsrvAll) => self.msrv_all()?, Some(CiCmd::MsrvAll) => self.msrv_all()?,
Some(CiCmd::MsrvClient) => self.msrv_client()?, Some(CiCmd::MsrvClient) => self.msrv_client()?,
Some(CiCmd::MsrvRuma) => self.msrv_ruma()?, Some(CiCmd::MsrvRuma) => self.msrv_ruma()?,
Some(CiCmd::MsrvOwnedIdBox) => self.msrv_owned_id_box()?,
Some(CiCmd::MsrvOwnedIdArc) => self.msrv_owned_id_arc()?,
Some(CiCmd::Stable) => self.stable()?, Some(CiCmd::Stable) => self.stable()?,
Some(CiCmd::StableAll) => self.stable_all()?, Some(CiCmd::StableAll) => self.stable_all()?,
Some(CiCmd::StableClient) => self.stable_client()?, Some(CiCmd::StableClient) => self.stable_client()?,
@ -210,6 +216,22 @@ impl CiTask {
cmd!("rustup run {NIGHTLY} cargo check -p ruma --features full").run().map_err(Into::into) cmd!("rustup run {NIGHTLY} cargo check -p ruma --features full").run().map_err(Into::into)
} }
/// Check ruma-common with `ruma_identifiers_storage="Box"`
fn msrv_owned_id_box(&self) -> Result<()> {
cmd!("rustup run {MSRV} cargo check -p ruma-common")
.env("RUSTFLAGS", "--cfg=ruma_identifiers_storage=\"Box\"")
.run()
.map_err(Into::into)
}
/// Check ruma-common with `ruma_identifiers_storage="Arc"`
fn msrv_owned_id_arc(&self) -> Result<()> {
cmd!("rustup run {MSRV} cargo check -p ruma-common")
.env("RUSTFLAGS", "--cfg=ruma_identifiers_storage=\"Arc\"")
.run()
.map_err(Into::into)
}
/// Lint default features with clippy with the nightly version. /// Lint default features with clippy with the nightly version.
fn clippy_default(&self) -> Result<()> { fn clippy_default(&self) -> Result<()> {
cmd!( cmd!(