various identifiers macro optimizations

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-12-28 17:12:37 +00:00
parent 6e4d02b9c0
commit 30a08ff7be
10 changed files with 217 additions and 101 deletions

View File

@ -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);
}

View File

@ -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::<OwnedServerName>())
.unwrap_or_else(|| Err(MatrixToError::UnknownArgument.into()))
})
.collect::<Result<Vec<_>, _>>()

View File

@ -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()
}

View File

@ -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 {

View File

@ -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);

View File

@ -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<str> + Into<Box<str>>,
id: impl AsRef<str> + Into<String>,
server_name: &ServerName,
) -> Result<OwnedUserId, IdParseError> {
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))
}

View File

@ -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<Self> {
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<SystemTime> {
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<Self> {
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<SystemTime> {
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
}

View File

@ -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 })

View File

@ -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())),
},
};

View File

@ -49,9 +49,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
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<TokenStream> {
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<TokenStream> {
};
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<TokenStream> {
#[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<str>) -> Box<Self> {
unsafe { Box::from_raw(Box::into_raw(s) as _) }
}
#[inline]
pub(super) fn from_rc(s: std::rc::Rc<str>) -> std::rc::Rc<Self> {
unsafe { std::rc::Rc::from_raw(std::rc::Rc::into_raw(s) as _) }
}
#[inline]
pub(super) fn from_arc(s: std::sync::Arc<str>) -> std::sync::Arc<Self> {
unsafe { std::sync::Arc::from_raw(std::sync::Arc::into_raw(s) as _) }
}
#[inline]
pub(super) fn into_owned(self: Box<Self>) -> #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<TokenStream> {
#sv::from_vec(v)
}
#[inline]
pub(super) fn into_box(s: Box<Self>) -> Box<str> {
unsafe { Box::from_raw(Box::into_raw(s) as _) }
}
@ -136,17 +142,9 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
}
}
#[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<TokenStream> {
#[automatically_derived]
impl #impl_generics AsRef<str> 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<TokenStream> {
#[automatically_derived]
impl #impl_generics AsRef<str> 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<TokenStream> {
#[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<TokenStream> {
#[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<TokenStream> {
#[automatically_derived]
impl #impl_generics From<Box<#id_ty>> 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<TokenStream> {
#[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<TokenStream> {
#[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<TokenStream> {
#[automatically_derived]
impl #impl_generics PartialEq<Box<#id_ty>> 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<TokenStream> {
#[automatically_derived]
impl #impl_generics PartialEq<Box<#id_ty>> 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<str> 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<H: std::hash::Hasher>(&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<std::sync::Arc<#id_ty>> 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<str> = 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<std::cmp::Ordering> {
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<H>(&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<Box<#id_ty>> 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<std::sync::Arc<#id_ty>> 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: S) -> Result<#owned_ty, crate::IdParseError>
where
S: Into<String> + 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<str>,
) -> Result<#owned_ty, crate::IdParseError> {
pub fn parse<S>(s: &S) -> Result<&'_ #id_ty, crate::IdParseError>
where
S: AsRef<str> + ?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<u8> = s.into();
Ok(<#owned_ty>::new(s.into()))
}
#[inline]
#[doc = #parse_doc_header]
fn parse_owned(s: impl AsRef<str>) -> 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<str> + Into<Box<str>>,
) -> Result<Box<Self>, 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<str> + Into<std::rc::Rc<str>>,
) -> Result<std::rc::Rc<Self>, 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<str> + Into<std::sync::Arc<str>>,
) -> Result<std::sync::Arc<Self>, 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<D>(deserializer: D) -> Result<Self, D::Error>
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<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
let s = <&'de str>::deserialize(deserializer)?;
let s = Box::<str>::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<Self, Self::Error> {
#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<Self, Self::Error> {
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<Self, Self::Error> {
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<Option<&'a serde_json::Value>> for &'a #id_ty {
type Error = crate::IdParseError;
#[inline]
fn try_from(v: Option<&'a serde_json::Value>) -> Result<Self, Self::Error> {
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<Option<&'a crate::CanonicalJsonValue>> for &'a #id_ty {
type Error = crate::IdParseError;
#[inline]
fn try_from(v: Option<&'a crate::CanonicalJsonValue>) -> Result<Self, Self::Error> {
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<Self, Self::Err> {
<#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<Self, Self::Error> {
<#id_ty>::parse_box(s)
}
@ -661,6 +750,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
impl #impl_generics std::convert::TryFrom<String> for Box<#id_ty> {
type Error = crate::IdParseError;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> {
<#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<Self, Self::Err> {
<#id_ty>::parse(s)
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
<#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<Self, Self::Error> {
<#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<String> for #owned_ty {
type Error = crate::IdParseError;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> {
<#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<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Box::<str>::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::<str>::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<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
<&'de str>::deserialize(deserializer).map(<#id_ty>::from_borrowed).map(Into::into)
Box::<str>::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 {
<str as std::fmt::Debug>::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::<str>::as_ref(self) == AsRef::<str>::as_ref(other)
}