diff --git a/crates/ruma-common/src/identifiers/key_id.rs b/crates/ruma-common/src/identifiers/key_id.rs index d7f24e4f..2bdcef2d 100644 --- a/crates/ruma-common/src/identifiers/key_id.rs +++ b/crates/ruma-common/src/identifiers/key_id.rs @@ -213,27 +213,27 @@ mod tests { #[test] fn algorithm_and_key_name_are_correctly_extracted() { - let key_id = DeviceKeyId::parse("ed25519:MYDEVICE").expect("Should parse correctly"); + let key_id = DeviceKeyId::parse_ref("ed25519:MYDEVICE").expect("Should parse correctly"); assert_eq!(key_id.algorithm().as_str(), "ed25519"); assert_eq!(key_id.key_name(), "MYDEVICE"); } #[test] fn empty_key_name_is_correctly_extracted() { - let key_id = DeviceKeyId::parse("ed25519:").expect("Should parse correctly"); + let key_id = DeviceKeyId::parse_ref("ed25519:").expect("Should parse correctly"); assert_eq!(key_id.algorithm().as_str(), "ed25519"); assert_eq!(key_id.key_name(), ""); } #[test] fn missing_colon_fails_to_parse() { - let error = DeviceKeyId::parse("ed25519_MYDEVICE").expect_err("Should fail to parse"); + let error = DeviceKeyId::parse_ref("ed25519_MYDEVICE").expect_err("Should fail to parse"); assert_matches!(error, Error::MissingColon); } #[test] fn empty_algorithm_fails_to_parse() { - let error = DeviceKeyId::parse(":MYDEVICE").expect_err("Should fail to parse"); + let error = DeviceKeyId::parse_ref(":MYDEVICE").expect_err("Should fail to parse"); // Weirdly, this also reports MissingColon assert_matches!(error, Error::MissingColon); } diff --git a/crates/ruma-common/src/identifiers/matrix_uri.rs b/crates/ruma-common/src/identifiers/matrix_uri.rs index 867ffbb2..e2d890cb 100644 --- a/crates/ruma-common/src/identifiers/matrix_uri.rs +++ b/crates/ruma-common/src/identifiers/matrix_uri.rs @@ -13,7 +13,7 @@ use super::{ EventId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, OwnedUserId, RoomAliasId, RoomId, RoomOrAliasId, UserId, }; -use crate::{percent_encode::PATH_PERCENT_ENCODE_SET, PrivOwnedStr, ServerName}; +use crate::{percent_encode::PATH_PERCENT_ENCODE_SET, PrivOwnedStr}; const MATRIX_TO_BASE_URL: &str = "https://matrix.to/#/"; const MATRIX_SCHEME: &str = "matrix"; @@ -315,7 +315,7 @@ impl MatrixToUri { query_parts .map(|(key, value)| { (key == "via") - .then(|| ServerName::parse(&value)) + .then(|| value.parse::()) .unwrap_or_else(|| Err(MatrixToError::UnknownArgument.into())) }) .collect::, _>>() diff --git a/crates/ruma-common/src/identifiers/room_id.rs b/crates/ruma-common/src/identifiers/room_id.rs index a5900ff6..4893fc7b 100644 --- a/crates/ruma-common/src/identifiers/room_id.rs +++ b/crates/ruma-common/src/identifiers/room_id.rs @@ -20,7 +20,10 @@ use crate::RoomOrAliasId; /// [room ID]: https://spec.matrix.org/latest/appendices/#room-ids #[repr(transparent)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] -#[ruma_id(validate = ruma_identifiers_validation::room_id::validate)] +#[ruma_id( + validate = ruma_identifiers_validation::room_id::validate, + inline_bytes = 48 +)] pub struct RoomId(str); impl RoomId { @@ -35,6 +38,7 @@ impl RoomId { } /// Returns the server name of the room ID. + #[inline] pub fn server_name(&self) -> Option<&ServerName> { <&RoomOrAliasId>::from(self).server_name() } diff --git a/crates/ruma-common/src/identifiers/room_or_alias_id.rs b/crates/ruma-common/src/identifiers/room_or_alias_id.rs index f52dc559..dc09c54a 100644 --- a/crates/ruma-common/src/identifiers/room_or_alias_id.rs +++ b/crates/ruma-common/src/identifiers/room_or_alias_id.rs @@ -27,7 +27,10 @@ use super::{server_name::ServerName, OwnedRoomAliasId, OwnedRoomId, RoomAliasId, /// [room alias ID]: https://spec.matrix.org/latest/appendices/#room-aliases #[repr(transparent)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] -#[ruma_id(validate = ruma_identifiers_validation::room_id_or_alias_id::validate)] +#[ruma_id( + validate = ruma_identifiers_validation::room_id_or_alias_id::validate, + inline_bytes = 48 +)] pub struct RoomOrAliasId(str); impl RoomOrAliasId { diff --git a/crates/ruma-common/src/identifiers/server_signing_key_version.rs b/crates/ruma-common/src/identifiers/server_signing_key_version.rs index 4425d2df..d4bf54f9 100644 --- a/crates/ruma-common/src/identifiers/server_signing_key_version.rs +++ b/crates/ruma-common/src/identifiers/server_signing_key_version.rs @@ -15,6 +15,7 @@ use super::{IdParseError, KeyName}; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] #[ruma_id( validate = ruma_identifiers_validation::server_signing_key_version::validate, + inline_bytes = 16 )] pub struct ServerSigningKeyVersion(str); diff --git a/crates/ruma-common/src/identifiers/user_id.rs b/crates/ruma-common/src/identifiers/user_id.rs index be271a59..8ea751dc 100644 --- a/crates/ruma-common/src/identifiers/user_id.rs +++ b/crates/ruma-common/src/identifiers/user_id.rs @@ -17,7 +17,10 @@ use super::{matrix_uri::UriAction, IdParseError, MatrixToUri, MatrixUri, ServerN /// [user ID]: https://spec.matrix.org/latest/appendices/#user-identifiers #[repr(transparent)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] -#[ruma_id(validate = ruma_identifiers_validation::user_id::validate)] +#[ruma_id( + validate = ruma_identifiers_validation::user_id::validate, + inline_bytes = 40, +)] pub struct UserId(str); impl UserId { @@ -42,13 +45,13 @@ 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: &ServerName, ) -> Result { let id_str = id.as_ref(); if id_str.starts_with('@') { - Self::parse(id).map(Into::into) + Self::parse_into_owned(id.into()) } else { let _ = localpart_is_fully_conforming(id_str)?; Ok(Self::from_borrowed(&format!("@{id_str}:{server_name}")).to_owned()) @@ -103,6 +106,7 @@ impl UserId { /// /// A historical user ID is one that doesn't conform to the latest specification of the user ID /// grammar but is still accepted because it was previously allowed. + #[inline] pub fn is_historical(&self) -> bool { !localpart_is_fully_conforming(self.localpart()).unwrap() } @@ -120,6 +124,7 @@ impl UserId { /// display_name = "jplatte", /// ); /// ``` + #[inline] pub fn matrix_to_uri(&self) -> MatrixToUri { MatrixToUri::new(self.into(), Vec::new()) } @@ -140,6 +145,7 @@ impl UserId { /// display_name = "jplatte", /// ); /// ``` + #[inline] pub fn matrix_uri(&self, chat: bool) -> MatrixUri { MatrixUri::new(self.into(), Vec::new(), Some(UriAction::Chat).filter(|_| chat)) } diff --git a/crates/ruma-common/src/time.rs b/crates/ruma-common/src/time.rs index b795b53e..a4c7e85d 100644 --- a/crates/ruma-common/src/time.rs +++ b/crates/ruma-common/src/time.rs @@ -14,6 +14,7 @@ pub struct MilliSecondsSinceUnixEpoch(pub UInt); impl MilliSecondsSinceUnixEpoch { /// Creates a new `MilliSecondsSinceUnixEpoch` from the given `SystemTime`, if it is not before /// the unix epoch, or too large to be represented. + #[inline] pub fn from_system_time(time: SystemTime) -> Option { let duration = time.duration_since(UNIX_EPOCH).ok()?; let millis = duration.as_millis().try_into().ok()?; @@ -21,6 +22,7 @@ impl MilliSecondsSinceUnixEpoch { } /// The current system time in milliseconds since the unix epoch. + #[inline] pub fn now() -> Self { #[cfg(not(all(target_arch = "wasm32", target_os = "unknown", feature = "js")))] return Self::from_system_time(SystemTime::now()).expect("date out of range"); @@ -30,16 +32,19 @@ impl MilliSecondsSinceUnixEpoch { } /// Creates a new `SystemTime` from `self`, if it can be represented. + #[inline] pub fn to_system_time(self) -> Option { UNIX_EPOCH.checked_add(Duration::from_millis(self.0.into())) } /// Get the time since the unix epoch in milliseconds. + #[inline] pub fn get(&self) -> UInt { self.0 } /// Get time since the unix epoch in seconds. + #[inline] pub fn as_secs(&self) -> UInt { self.0 / uint!(1000) } @@ -81,6 +86,7 @@ pub struct SecondsSinceUnixEpoch(pub UInt); impl SecondsSinceUnixEpoch { /// Creates a new `MilliSecondsSinceUnixEpoch` from the given `SystemTime`, if it is not before /// the unix epoch, or too large to be represented. + #[inline] pub fn from_system_time(time: SystemTime) -> Option { let duration = time.duration_since(UNIX_EPOCH).ok()?; let millis = duration.as_secs().try_into().ok()?; @@ -88,6 +94,7 @@ impl SecondsSinceUnixEpoch { } /// The current system-time as seconds since the unix epoch. + #[inline] pub fn now() -> Self { #[cfg(not(all(target_arch = "wasm32", target_os = "unknown", feature = "js")))] return Self::from_system_time(SystemTime::now()).expect("date out of range"); @@ -97,11 +104,13 @@ impl SecondsSinceUnixEpoch { } /// Creates a new `SystemTime` from `self`, if it can be represented. + #[inline] pub fn to_system_time(self) -> Option { UNIX_EPOCH.checked_add(Duration::from_secs(self.0.into())) } /// Get time since the unix epoch in seconds. + #[inline] pub fn get(&self) -> UInt { self.0 } diff --git a/crates/ruma-events/src/call/member/member_state_key.rs b/crates/ruma-events/src/call/member/member_state_key.rs index f50cb773..7466eff8 100644 --- a/crates/ruma-events/src/call/member/member_state_key.rs +++ b/crates/ruma-events/src/call/member/member_state_key.rs @@ -149,7 +149,7 @@ impl FromStr for CallMemberStateKeyEnum { if underscore { Err(KeyParseError::LeadingUnderscoreNoDevice) } else { - Ok(CallMemberStateKeyEnum::new(user_id, None, underscore)) + Ok(CallMemberStateKeyEnum::new(user_id.into(), None, underscore)) } } Err(err) => Err(KeyParseError::InvalidUser { @@ -168,7 +168,7 @@ impl FromStr for CallMemberStateKeyEnum { if device_id.as_str().is_empty() { return Err(KeyParseError::EmptyDevice); }; - Ok(CallMemberStateKeyEnum::new(user_id, Some(device_id), underscore)) + Ok(CallMemberStateKeyEnum::new(user_id.into(), Some(device_id), underscore)) } (Err(err), _) => { Err(KeyParseError::InvalidUser { user_id: user_id.to_owned(), error: err }) diff --git a/crates/ruma-events/src/receipt.rs b/crates/ruma-events/src/receipt.rs index 424c89c0..41dcd0cb 100644 --- a/crates/ruma-events/src/receipt.rs +++ b/crates/ruma-events/src/receipt.rs @@ -200,7 +200,7 @@ where None => Self::Unthreaded, Some(s) => match s.as_ref() { "main" => Self::Main, - s_ref if s_ref.starts_with('$') => Self::Thread(EventId::parse(s_ref)?), + s_ref if s_ref.starts_with('$') => Self::Thread(EventId::parse(s_ref)?.into()), _ => Self::_Custom(PrivOwnedStr(s.into())), }, }; diff --git a/crates/ruma-macros/src/identifiers.rs b/crates/ruma-macros/src/identifiers.rs index 19f019d7..3bd1263f 100644 --- a/crates/ruma-macros/src/identifiers.rs +++ b/crates/ruma-macros/src/identifiers.rs @@ -49,9 +49,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { assert_eq!(where_clause, None, "where clauses on identifier types are not currently supported"); let id = &input.ident; - let owned = format_ident!("Owned{id}"); let id_ty = quote! { #id #ty_generics }; - let owned_ty = quote! { #owned #ty_generics }; const INLINE_BYTES: usize = 32; let inline_bytes = meta.inline_bytes.unwrap_or(INLINE_BYTES); @@ -59,7 +57,9 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { let sv_decl = quote! { smallvec::SmallVec<#inline_array> }; let sv = quote! { smallvec::SmallVec::<#inline_array> }; - let owned_decl = expand_owned_id(&input, inline_bytes); + let as_str_docs = format!("Creates a string slice from this `{id}`."); + let as_bytes_docs = format!("Creates a byte slice from this `{id}`."); + let max_bytes_docs = format!("Maximum byte length for any `{id}`."); let as_str_impl = match &input.fields { Fields::Named(_) | Fields::Unit => { @@ -73,12 +73,12 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { }; let as_str_impls = expand_as_str_impls(id_ty.clone(), &impl_generics); + let partial_eq_string = expand_partial_eq_string(id_ty.clone(), &impl_generics); + // FIXME: Remove? let box_partial_eq_string = expand_partial_eq_string(quote! { Box<#id_ty> }, &impl_generics); - let as_str_docs = format!("Creates a string slice from this `{id}`."); - let as_bytes_docs = format!("Creates a byte slice from this `{id}`."); - let max_bytes_docs = format!("Maximum byte length for any `{id}`."); + let owned_decl = expand_owned_id(&input, inline_bytes); Ok(quote! { #owned_decl @@ -89,22 +89,27 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[doc = #max_bytes_docs] pub const MAX_BYTES: usize = ruma_identifiers_validation::MAX_BYTES; + #[inline] pub(super) const fn from_borrowed(s: &str) -> &Self { unsafe { std::mem::transmute(s) } } + #[inline] pub(super) fn from_box(s: Box) -> Box { unsafe { Box::from_raw(Box::into_raw(s) as _) } } + #[inline] pub(super) fn from_rc(s: std::rc::Rc) -> std::rc::Rc { unsafe { std::rc::Rc::from_raw(std::rc::Rc::into_raw(s) as _) } } + #[inline] pub(super) fn from_arc(s: std::sync::Arc) -> std::sync::Arc { unsafe { std::sync::Arc::from_raw(std::sync::Arc::into_raw(s) as _) } } + #[inline] pub(super) fn into_owned(self: Box) -> #sv_decl { let len = self.as_bytes().len(); let p: *mut u8 = Box::into_raw(self).cast(); @@ -112,6 +117,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #sv::from_vec(v) } + #[inline] pub(super) fn into_box(s: Box) -> Box { unsafe { Box::from_raw(Box::into_raw(s) as _) } } @@ -136,17 +142,9 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { } } - #[automatically_derived] - impl #impl_generics ToOwned for #id_ty { - type Owned = #owned_ty; - - fn to_owned(&self) -> Self::Owned { - Self::Owned::new(self.as_bytes().into()) - } - } - #[automatically_derived] impl #impl_generics AsRef<#id_ty> for #id_ty { + #[inline] fn as_ref(&self) -> &#id_ty { self } @@ -154,6 +152,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics AsRef for #id_ty { + #[inline] fn as_ref(&self) -> &str { self.as_str() } @@ -161,6 +160,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics AsRef for Box<#id_ty> { + #[inline] fn as_ref(&self) -> &str { self.as_str() } @@ -168,6 +168,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics AsRef<[u8]> for #id_ty { + #[inline] fn as_ref(&self) -> &[u8] { self.as_bytes() } @@ -175,11 +176,14 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics AsRef<[u8]> for Box<#id_ty> { + #[inline] fn as_ref(&self) -> &[u8] { self.as_bytes() } } + #as_str_impls + #[automatically_derived] impl #impl_generics From<&#id_ty> for String { fn from(id: &#id_ty) -> Self { @@ -189,6 +193,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics From> for String { + #[inline] fn from(id: Box<#id_ty>) -> Self { String::from(<#id_ty>::into_box(id)) } @@ -219,6 +224,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics PartialEq<#id_ty> for Box<#id_ty> { + #[inline] fn eq(&self, other: &#id_ty) -> bool { self.as_str() == other.as_str() } @@ -226,6 +232,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics PartialEq<&'_ #id_ty> for Box<#id_ty> { + #[inline] fn eq(&self, other: &&#id_ty) -> bool { self.as_str() == other.as_str() } @@ -233,6 +240,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics PartialEq> for #id_ty { + #[inline] fn eq(&self, other: &Box<#id_ty>) -> bool { self.as_str() == other.as_str() } @@ -240,13 +248,15 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result { #[automatically_derived] impl #impl_generics PartialEq> for &'_ #id_ty { + #[inline] fn eq(&self, other: &Box<#id_ty>) -> bool { self.as_str() == other.as_str() } } - #as_str_impls + #partial_eq_string #box_partial_eq_string + #extra_impls }) } @@ -278,6 +288,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { }; let as_str_impls = expand_as_str_impls(owned_ty.clone(), &impl_generics); + let partial_eq_string = expand_partial_eq_string(owned_ty.clone(), &impl_generics); let doc_header = format!("Owned variant of {id}"); @@ -300,6 +311,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics AsRef<#id_ty> for #owned_ty { + #[inline] fn as_ref(&self) -> &#id_ty { let s: &str = self.as_ref(); <#id_ty>::from_borrowed(s) @@ -308,6 +320,15 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics AsRef for #owned_ty { + #[inline] + #[cfg(debug_assertions)] + fn as_ref(&self) -> &str { + let s: &[u8] = self.as_ref(); + std::str::from_utf8(s).expect("identifier buffer contained invalid utf8") + } + + #[inline] + #[cfg(not(debug_assertions))] fn as_ref(&self) -> &str { let s: &[u8] = self.as_ref(); unsafe { std::str::from_utf8_unchecked(s) } @@ -316,17 +337,13 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics AsRef<[u8]> for #owned_ty { + #[inline] fn as_ref(&self) -> &[u8] { self.inner.as_slice() } } - #[automatically_derived] - impl #impl_generics From<#owned_ty> for String { - fn from(id: #owned_ty) -> String { - unsafe { String::from_utf8_unchecked(id.inner.into_vec()) } - } - } + #as_str_impls #[automatically_derived] impl #impl_generics std::clone::Clone for #owned_ty { @@ -339,18 +356,36 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { impl #impl_generics std::ops::Deref for #owned_ty { type Target = #id_ty; + #[inline] fn deref(&self) -> &Self::Target { self.as_ref() } } + #[automatically_derived] + impl #impl_generics std::borrow::ToOwned for #id_ty { + type Owned = #owned_ty; + + fn to_owned(&self) -> Self::Owned { + Self::Owned::new(self.as_bytes().into()) + } + } + #[automatically_derived] impl #impl_generics std::borrow::Borrow<#id_ty> for #owned_ty { + #[inline] fn borrow(&self) -> &#id_ty { self.as_ref() } } + #[automatically_derived] + impl #impl_generics std::hash::Hash for #owned_ty { + fn hash(&self, state: &mut H) { + self.as_str().hash(state) + } + } + #[automatically_derived] impl #impl_generics From<&'_ #id_ty> for #owned_ty { fn from(id: &#id_ty) -> #owned_ty { @@ -367,37 +402,55 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics From> for #owned_ty { - fn from(a: std::sync::Arc<#id_ty>) -> #owned_ty { - Self::new(a.as_bytes().into()) //TODO + fn from(id: std::sync::Arc<#id_ty>) -> #owned_ty { + (*id).to_owned() + } + } + + #[automatically_derived] + impl #impl_generics From<#owned_ty> for String { + #[cfg(debug_assertions)] + fn from(id: #owned_ty) -> String { + String::from_utf8(id.inner.into_vec()).expect("identifier buffer contained invalid utf8") + } + + #[cfg(not(debug_assertions))] + fn from(id: #owned_ty) -> String { + unsafe { String::from_utf8_unchecked(id.inner.into_vec()) } } } #[automatically_derived] impl #impl_generics From<#owned_ty> for Box<#id_ty> { - fn from(a: #owned_ty) -> Box<#id_ty> { - { Box::from(<#id_ty>::from_borrowed(a.as_str())) } + fn from(id: #owned_ty) -> Box<#id_ty> { + let id: String = id.into(); + let id: Box = id.into_boxed_str(); + <#id_ty>::from_box(id) } } #[automatically_derived] impl #impl_generics From<#owned_ty> for std::sync::Arc<#id_ty> { - fn from(a: #owned_ty) -> std::sync::Arc<#id_ty> { - { std::sync::Arc::from(<#id_ty>::from_borrowed(a.as_str())) } - } - } - - #[automatically_derived] - impl #impl_generics std::cmp::PartialEq for #owned_ty { - fn eq(&self, other: &Self) -> bool { - self.as_str() == other.as_str() + fn from(id: #owned_ty) -> std::sync::Arc<#id_ty> { + let id: Box<#id_ty> = id.into(); + std::sync::Arc::from(id) } } #[automatically_derived] impl #impl_generics std::cmp::Eq for #owned_ty {} + #[automatically_derived] + impl #impl_generics std::cmp::PartialEq for #owned_ty { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.as_str() == other.as_str() + } + } + #[automatically_derived] impl #impl_generics std::cmp::PartialOrd for #owned_ty { + #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } @@ -405,25 +458,15 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics std::cmp::Ord for #owned_ty { + #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_str().cmp(other.as_str()) } } - #[automatically_derived] - impl #impl_generics std::hash::Hash for #owned_ty { - fn hash(&self, state: &mut H) - where - H: std::hash::Hasher, - { - self.as_str().hash(state) - } - } - - #as_str_impls - #[automatically_derived] impl #impl_generics PartialEq<#id_ty> for #owned_ty { + #[inline] fn eq(&self, other: &#id_ty) -> bool { AsRef::<#id_ty>::as_ref(self) == other } @@ -431,6 +474,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics PartialEq<#owned_ty> for #id_ty { + #[inline] fn eq(&self, other: &#owned_ty) -> bool { self == AsRef::<#id_ty>::as_ref(other) } @@ -438,6 +482,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics PartialEq<&#id_ty> for #owned_ty { + #[inline] fn eq(&self, other: &&#id_ty) -> bool { AsRef::<#id_ty>::as_ref(self) == *other } @@ -445,6 +490,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics PartialEq<#owned_ty> for &#id_ty { + #[inline] fn eq(&self, other: &#owned_ty) -> bool { *self == AsRef::<#id_ty>::as_ref(other) } @@ -452,6 +498,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics PartialEq> for #owned_ty { + #[inline] fn eq(&self, other: &Box<#id_ty>) -> bool { AsRef::<#id_ty>::as_ref(self) == AsRef::<#id_ty>::as_ref(other) } @@ -459,6 +506,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics PartialEq<#owned_ty> for Box<#id_ty> { + #[inline] fn eq(&self, other: &#owned_ty) -> bool { AsRef::<#id_ty>::as_ref(self) == AsRef::<#id_ty>::as_ref(other) } @@ -466,6 +514,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics PartialEq> for #owned_ty { + #[inline] fn eq(&self, other: &std::sync::Arc<#id_ty>) -> bool { AsRef::<#id_ty>::as_ref(self) == AsRef::<#id_ty>::as_ref(other) } @@ -473,10 +522,13 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream { #[automatically_derived] impl #impl_generics PartialEq<#owned_ty> for std::sync::Arc<#id_ty> { + #[inline] fn eq(&self, other: &#owned_ty) -> bool { AsRef::<#id_ty>::as_ref(self) == AsRef::<#id_ty>::as_ref(other) } } + + #partial_eq_string } } @@ -495,26 +547,56 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { let parse_arc_docs = format!("Try parsing a `&str` into an `Arc<{id}>`."); quote! { + #[automatically_derived] + impl #impl_generics #owned_ty { + #[inline] + #[doc = #parse_doc_header] + pub fn parse(s: S) -> Result<#owned_ty, crate::IdParseError> + where + S: Into + Sized, + { + <#id_ty>::parse_owned(s.into()) + } + } + #[automatically_derived] impl #impl_generics #id_ty { #[inline] #[doc = #parse_doc_header] - /// - /// The same can also be done using `FromStr`, `TryFrom` or `TryInto`. - /// This function is simply more constrained and thus useful in generic contexts. - pub fn parse( - s: impl AsRef, - ) -> Result<#owned_ty, crate::IdParseError> { + pub fn parse(s: &S) -> Result<&'_ #id_ty, crate::IdParseError> + where + S: AsRef + ?Sized, + { + Self::parse_ref(s.as_ref()) + } + + #[doc = #parse_doc_header] + fn parse_into_owned(s: String) -> Result<#owned_ty, crate::IdParseError> { + #validate(s.as_str())?; + + let s: Vec = s.into(); + Ok(<#owned_ty>::new(s.into())) + } + + #[inline] + #[doc = #parse_doc_header] + fn parse_owned(s: impl AsRef) -> Result<#owned_ty, crate::IdParseError> { #validate(s.as_ref())?; - Ok((<#id_ty>::from_borrowed(s.as_ref())).to_owned()) + Ok(<#id_ty>::from_borrowed(s.as_ref()).to_owned()) + } + + #[inline] + #[doc = #parse_doc_header] + fn parse_ref<'a>( + s: &'a str, + ) -> Result<&'a #id_ty, crate::IdParseError> { + #validate(s)?; + Ok(<#id_ty>::from_borrowed(s)) } #[inline] #[doc = #parse_box_doc_header] - /// - /// The same can also be done using `FromStr`, `TryFrom` or `TryInto`. - /// This function is simply more constrained and thus useful in generic contexts. - pub fn parse_box( + fn parse_box( s: impl AsRef + Into>, ) -> Result, crate::IdParseError> { #validate(s.as_ref())?; @@ -523,7 +605,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { #[inline] #[doc = #parse_rc_docs] - pub fn parse_rc( + fn parse_rc( s: impl AsRef + Into>, ) -> Result, crate::IdParseError> { #validate(s.as_ref())?; @@ -532,7 +614,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { #[inline] #[doc = #parse_arc_docs] - pub fn parse_arc( + fn parse_arc( s: impl AsRef + Into>, ) -> Result, crate::IdParseError> { #validate(s.as_ref())?; @@ -541,18 +623,18 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { } #[automatically_derived] - impl<'de, #generic_params> serde::Deserialize<'de> for Box<#id_ty> { + impl<'de, #generic_params> serde::Deserialize<'de> for &'de #id_ty { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { use serde::de::Error; - let s = String::deserialize(deserializer)?; + let s = <&'de str>::deserialize(deserializer)?; - match <#id_ty>::parse_box(s) { - Ok(o) => Ok(o), + match <#id_ty>::parse_ref(s) { Err(e) => Err(D::Error::custom(e)), + Ok(o) => Ok(o), } } } @@ -567,26 +649,26 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { let s = String::deserialize(deserializer)?; - match <#id_ty>::parse(s) { - Ok(o) => Ok(o), + match <#id_ty>::parse_into_owned(s) { Err(e) => Err(D::Error::custom(e)), + Ok(o) => Ok(o), } } } #[automatically_derived] - impl<'de, #generic_params> serde::Deserialize<'de> for &'de #id_ty { + impl<'de, #generic_params> serde::Deserialize<'de> for Box<#id_ty> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { use serde::de::Error; - let s = <&'de str>::deserialize(deserializer)?; + let s = Box::::deserialize(deserializer)?; - match #validate(s) { - Ok(_) => Ok(<#id_ty>::from_borrowed(s)), + match <#id_ty>::parse_box(s) { Err(e) => Err(D::Error::custom(e)), + Ok(o) => Ok(o), } } } @@ -595,6 +677,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl<'a, #generic_params> std::convert::TryFrom<&'a str> for &'a #id_ty { type Error = crate::IdParseError; + #[inline] fn try_from(s: &'a str) -> Result { #validate(s)?; Ok(<#id_ty>::from_borrowed(s)) @@ -605,8 +688,9 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl<'a, #generic_params> std::convert::TryFrom<&'a serde_json::Value> for &'a #id_ty { type Error = crate::IdParseError; + #[inline] fn try_from(v: &'a serde_json::Value) -> Result { - v.as_str().unwrap_or_default().try_into() + <#id_ty>::parse_ref(v.as_str().unwrap_or_default()) } } @@ -615,8 +699,9 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl<'a, #generic_params> std::convert::TryFrom<&'a crate::CanonicalJsonValue> for &'a #id_ty { type Error = crate::IdParseError; + #[inline] fn try_from(v: &'a crate::CanonicalJsonValue) -> Result { - v.as_str().unwrap_or_default().try_into() + <#id_ty>::parse_ref(v.as_str().unwrap_or_default()) } } @@ -624,8 +709,9 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl<'a, #generic_params> std::convert::TryFrom> for &'a #id_ty { type Error = crate::IdParseError; + #[inline] fn try_from(v: Option<&'a serde_json::Value>) -> Result { - v.and_then(|v| v.as_str()).unwrap_or_default().try_into() + <#id_ty>::parse_ref(v.map(|v| v.as_str()).flatten().unwrap_or_default()) } } @@ -634,8 +720,9 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl<'a, #generic_params> std::convert::TryFrom> for &'a #id_ty { type Error = crate::IdParseError; + #[inline] fn try_from(v: Option<&'a crate::CanonicalJsonValue>) -> Result { - v.and_then(|v| v.as_str()).unwrap_or_default().try_into() + <#id_ty>::parse_ref(v.map(|v| v.as_str()).flatten().unwrap_or_default()) } } @@ -643,6 +730,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl #impl_generics std::str::FromStr for Box<#id_ty> { type Err = crate::IdParseError; + #[inline] fn from_str(s: &str) -> Result { <#id_ty>::parse_box(s) } @@ -652,6 +740,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl #impl_generics std::convert::TryFrom<&str> for Box<#id_ty> { type Error = crate::IdParseError; + #[inline] fn try_from(s: &str) -> Result { <#id_ty>::parse_box(s) } @@ -661,6 +750,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl #impl_generics std::convert::TryFrom for Box<#id_ty> { type Error = crate::IdParseError; + #[inline] fn try_from(s: String) -> Result { <#id_ty>::parse_box(s.into_boxed_str()) } @@ -670,8 +760,9 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl #impl_generics std::str::FromStr for #owned_ty { type Err = crate::IdParseError; - fn from_str(s: &str) -> Result { - <#id_ty>::parse(s) + #[inline] + fn from_str(s: &str) -> Result { + <#id_ty>::parse_owned(s) } } @@ -679,8 +770,9 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl #impl_generics std::convert::TryFrom<&str> for #owned_ty { type Error = crate::IdParseError; + #[inline] fn try_from(s: &str) -> Result { - <#id_ty>::parse(s) + <#id_ty>::parse_owned(s) } } @@ -688,8 +780,9 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { impl #impl_generics std::convert::TryFrom for #owned_ty { type Error = crate::IdParseError; + #[inline] fn try_from(s: String) -> Result { - <#id_ty>::parse(s) + <#id_ty>::parse_into_owned(s) } } } @@ -707,6 +800,7 @@ fn expand_unchecked_impls(input: &ItemStruct) -> TokenStream { quote! { #[automatically_derived] impl<'a, #generic_params> From<&'a str> for &'a #id_ty { + #[inline] fn from(s: &'a str) -> Self { <#id_ty>::from_borrowed(s) } @@ -714,6 +808,7 @@ fn expand_unchecked_impls(input: &ItemStruct) -> TokenStream { #[automatically_derived] impl #impl_generics From<&str> for #owned_ty { + #[inline] fn from(s: &str) -> Self { <&#id_ty>::from(s).into() } @@ -764,12 +859,12 @@ fn expand_unchecked_impls(input: &ItemStruct) -> TokenStream { } #[automatically_derived] - impl<'de, #generic_params> serde::Deserialize<'de> for Box<#id_ty> { + impl<'de, #generic_params> serde::Deserialize<'de> for &'de #id_ty { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { - Box::::deserialize(deserializer).map(<#id_ty>::from_box) + <&'de str>::deserialize(deserializer).map(<#id_ty>::from_borrowed).map(Into::into) } } @@ -779,29 +874,27 @@ fn expand_unchecked_impls(input: &ItemStruct) -> TokenStream { where D: serde::Deserializer<'de>, { - // FIXME: Deserialize inner, convert that Box::::deserialize(deserializer).map(<#id_ty>::from_box).map(Into::into) } } #[automatically_derived] - impl<'de, #generic_params> serde::Deserialize<'de> for &'de #id_ty { + impl<'de, #generic_params> serde::Deserialize<'de> for Box<#id_ty> { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { - <&'de str>::deserialize(deserializer).map(<#id_ty>::from_borrowed).map(Into::into) + Box::::deserialize(deserializer).map(<#id_ty>::from_box) } } } } fn expand_as_str_impls(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -> TokenStream { - let partial_eq_string = expand_partial_eq_string(ty.clone(), impl_generics); - quote! { #[automatically_derived] impl #impl_generics std::fmt::Display for #ty { + #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.as_str()) } @@ -809,6 +902,7 @@ fn expand_as_str_impls(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -> Tok #[automatically_derived] impl #impl_generics std::fmt::Debug for #ty { + #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ::fmt(self.as_str(), f) } @@ -823,8 +917,6 @@ fn expand_as_str_impls(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -> Tok serializer.serialize_str(self.as_str()) } } - - #partial_eq_string } } @@ -841,6 +933,7 @@ fn expand_partial_eq_string(ty: TokenStream, impl_generics: &ImplGenerics<'_>) - quote! { #[automatically_derived] impl #impl_generics PartialEq<#rhs> for #lhs { + #[inline] fn eq(&self, other: &#rhs) -> bool { AsRef::::as_ref(self) == AsRef::::as_ref(other) }