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] #[test]
fn algorithm_and_key_name_are_correctly_extracted() { 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.algorithm().as_str(), "ed25519");
assert_eq!(key_id.key_name(), "MYDEVICE"); assert_eq!(key_id.key_name(), "MYDEVICE");
} }
#[test] #[test]
fn empty_key_name_is_correctly_extracted() { 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.algorithm().as_str(), "ed25519");
assert_eq!(key_id.key_name(), ""); assert_eq!(key_id.key_name(), "");
} }
#[test] #[test]
fn missing_colon_fails_to_parse() { 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); assert_matches!(error, Error::MissingColon);
} }
#[test] #[test]
fn empty_algorithm_fails_to_parse() { 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 // Weirdly, this also reports MissingColon
assert_matches!(error, Error::MissingColon); assert_matches!(error, Error::MissingColon);
} }

View File

@ -13,7 +13,7 @@ use super::{
EventId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, EventId, OwnedEventId, OwnedRoomAliasId, OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName,
OwnedUserId, RoomAliasId, RoomId, RoomOrAliasId, UserId, 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_TO_BASE_URL: &str = "https://matrix.to/#/";
const MATRIX_SCHEME: &str = "matrix"; const MATRIX_SCHEME: &str = "matrix";
@ -315,7 +315,7 @@ impl MatrixToUri {
query_parts query_parts
.map(|(key, value)| { .map(|(key, value)| {
(key == "via") (key == "via")
.then(|| ServerName::parse(&value)) .then(|| value.parse::<OwnedServerName>())
.unwrap_or_else(|| Err(MatrixToError::UnknownArgument.into())) .unwrap_or_else(|| Err(MatrixToError::UnknownArgument.into()))
}) })
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()

View File

@ -20,7 +20,10 @@ use crate::RoomOrAliasId;
/// [room ID]: https://spec.matrix.org/latest/appendices/#room-ids /// [room ID]: https://spec.matrix.org/latest/appendices/#room-ids
#[repr(transparent)] #[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] #[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); pub struct RoomId(str);
impl RoomId { impl RoomId {
@ -35,6 +38,7 @@ impl RoomId {
} }
/// Returns the server name of the room ID. /// Returns the server name of the room ID.
#[inline]
pub fn server_name(&self) -> Option<&ServerName> { pub fn server_name(&self) -> Option<&ServerName> {
<&RoomOrAliasId>::from(self).server_name() <&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 /// [room alias ID]: https://spec.matrix.org/latest/appendices/#room-aliases
#[repr(transparent)] #[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] #[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); pub struct RoomOrAliasId(str);
impl RoomOrAliasId { impl RoomOrAliasId {

View File

@ -15,6 +15,7 @@ use super::{IdParseError, KeyName};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)]
#[ruma_id( #[ruma_id(
validate = ruma_identifiers_validation::server_signing_key_version::validate, validate = ruma_identifiers_validation::server_signing_key_version::validate,
inline_bytes = 16
)] )]
pub struct ServerSigningKeyVersion(str); 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 /// [user ID]: https://spec.matrix.org/latest/appendices/#user-identifiers
#[repr(transparent)] #[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] #[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); pub struct UserId(str);
impl UserId { impl UserId {
@ -42,13 +45,13 @@ impl UserId {
/// localpart, not the localpart plus the `@` prefix, or the localpart plus server name without /// localpart, not the localpart plus the `@` prefix, or the localpart plus server name without
/// the `@` prefix. /// the `@` prefix.
pub fn parse_with_server_name( pub fn parse_with_server_name(
id: impl AsRef<str> + Into<Box<str>>, id: impl AsRef<str> + Into<String>,
server_name: &ServerName, server_name: &ServerName,
) -> Result<OwnedUserId, IdParseError> { ) -> Result<OwnedUserId, IdParseError> {
let id_str = id.as_ref(); let id_str = id.as_ref();
if id_str.starts_with('@') { if id_str.starts_with('@') {
Self::parse(id).map(Into::into) Self::parse_into_owned(id.into())
} else { } else {
let _ = localpart_is_fully_conforming(id_str)?; let _ = localpart_is_fully_conforming(id_str)?;
Ok(Self::from_borrowed(&format!("@{id_str}:{server_name}")).to_owned()) 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 /// 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. /// grammar but is still accepted because it was previously allowed.
#[inline]
pub fn is_historical(&self) -> bool { pub fn is_historical(&self) -> bool {
!localpart_is_fully_conforming(self.localpart()).unwrap() !localpart_is_fully_conforming(self.localpart()).unwrap()
} }
@ -120,6 +124,7 @@ impl UserId {
/// display_name = "jplatte", /// display_name = "jplatte",
/// ); /// );
/// ``` /// ```
#[inline]
pub fn matrix_to_uri(&self) -> MatrixToUri { pub fn matrix_to_uri(&self) -> MatrixToUri {
MatrixToUri::new(self.into(), Vec::new()) MatrixToUri::new(self.into(), Vec::new())
} }
@ -140,6 +145,7 @@ impl UserId {
/// display_name = "jplatte", /// display_name = "jplatte",
/// ); /// );
/// ``` /// ```
#[inline]
pub fn matrix_uri(&self, chat: bool) -> MatrixUri { pub fn matrix_uri(&self, chat: bool) -> MatrixUri {
MatrixUri::new(self.into(), Vec::new(), Some(UriAction::Chat).filter(|_| chat)) MatrixUri::new(self.into(), Vec::new(), Some(UriAction::Chat).filter(|_| chat))
} }

View File

@ -14,6 +14,7 @@ pub struct MilliSecondsSinceUnixEpoch(pub UInt);
impl MilliSecondsSinceUnixEpoch { impl MilliSecondsSinceUnixEpoch {
/// Creates a new `MilliSecondsSinceUnixEpoch` from the given `SystemTime`, if it is not before /// Creates a new `MilliSecondsSinceUnixEpoch` from the given `SystemTime`, if it is not before
/// the unix epoch, or too large to be represented. /// the unix epoch, or too large to be represented.
#[inline]
pub fn from_system_time(time: SystemTime) -> Option<Self> { pub fn from_system_time(time: SystemTime) -> Option<Self> {
let duration = time.duration_since(UNIX_EPOCH).ok()?; let duration = time.duration_since(UNIX_EPOCH).ok()?;
let millis = duration.as_millis().try_into().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. /// The current system time in milliseconds since the unix epoch.
#[inline]
pub fn now() -> Self { pub fn now() -> Self {
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown", feature = "js")))] #[cfg(not(all(target_arch = "wasm32", target_os = "unknown", feature = "js")))]
return Self::from_system_time(SystemTime::now()).expect("date out of range"); 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. /// Creates a new `SystemTime` from `self`, if it can be represented.
#[inline]
pub fn to_system_time(self) -> Option<SystemTime> { pub fn to_system_time(self) -> Option<SystemTime> {
UNIX_EPOCH.checked_add(Duration::from_millis(self.0.into())) UNIX_EPOCH.checked_add(Duration::from_millis(self.0.into()))
} }
/// Get the time since the unix epoch in milliseconds. /// Get the time since the unix epoch in milliseconds.
#[inline]
pub fn get(&self) -> UInt { pub fn get(&self) -> UInt {
self.0 self.0
} }
/// Get time since the unix epoch in seconds. /// Get time since the unix epoch in seconds.
#[inline]
pub fn as_secs(&self) -> UInt { pub fn as_secs(&self) -> UInt {
self.0 / uint!(1000) self.0 / uint!(1000)
} }
@ -81,6 +86,7 @@ pub struct SecondsSinceUnixEpoch(pub UInt);
impl SecondsSinceUnixEpoch { impl SecondsSinceUnixEpoch {
/// Creates a new `MilliSecondsSinceUnixEpoch` from the given `SystemTime`, if it is not before /// Creates a new `MilliSecondsSinceUnixEpoch` from the given `SystemTime`, if it is not before
/// the unix epoch, or too large to be represented. /// the unix epoch, or too large to be represented.
#[inline]
pub fn from_system_time(time: SystemTime) -> Option<Self> { pub fn from_system_time(time: SystemTime) -> Option<Self> {
let duration = time.duration_since(UNIX_EPOCH).ok()?; let duration = time.duration_since(UNIX_EPOCH).ok()?;
let millis = duration.as_secs().try_into().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. /// The current system-time as seconds since the unix epoch.
#[inline]
pub fn now() -> Self { pub fn now() -> Self {
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown", feature = "js")))] #[cfg(not(all(target_arch = "wasm32", target_os = "unknown", feature = "js")))]
return Self::from_system_time(SystemTime::now()).expect("date out of range"); 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. /// Creates a new `SystemTime` from `self`, if it can be represented.
#[inline]
pub fn to_system_time(self) -> Option<SystemTime> { pub fn to_system_time(self) -> Option<SystemTime> {
UNIX_EPOCH.checked_add(Duration::from_secs(self.0.into())) UNIX_EPOCH.checked_add(Duration::from_secs(self.0.into()))
} }
/// Get time since the unix epoch in seconds. /// Get time since the unix epoch in seconds.
#[inline]
pub fn get(&self) -> UInt { pub fn get(&self) -> UInt {
self.0 self.0
} }

View File

@ -149,7 +149,7 @@ impl FromStr for CallMemberStateKeyEnum {
if underscore { if underscore {
Err(KeyParseError::LeadingUnderscoreNoDevice) Err(KeyParseError::LeadingUnderscoreNoDevice)
} else { } else {
Ok(CallMemberStateKeyEnum::new(user_id, None, underscore)) Ok(CallMemberStateKeyEnum::new(user_id.into(), None, underscore))
} }
} }
Err(err) => Err(KeyParseError::InvalidUser { Err(err) => Err(KeyParseError::InvalidUser {
@ -168,7 +168,7 @@ impl FromStr for CallMemberStateKeyEnum {
if device_id.as_str().is_empty() { if device_id.as_str().is_empty() {
return Err(KeyParseError::EmptyDevice); 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(err), _) => {
Err(KeyParseError::InvalidUser { user_id: user_id.to_owned(), error: err }) Err(KeyParseError::InvalidUser { user_id: user_id.to_owned(), error: err })

View File

@ -200,7 +200,7 @@ where
None => Self::Unthreaded, None => Self::Unthreaded,
Some(s) => match s.as_ref() { Some(s) => match s.as_ref() {
"main" => Self::Main, "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())), _ => 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"); assert_eq!(where_clause, None, "where clauses on identifier types are not currently supported");
let id = &input.ident; let id = &input.ident;
let owned = format_ident!("Owned{id}");
let id_ty = quote! { #id #ty_generics }; let id_ty = quote! { #id #ty_generics };
let owned_ty = quote! { #owned #ty_generics };
const INLINE_BYTES: usize = 32; const INLINE_BYTES: usize = 32;
let inline_bytes = meta.inline_bytes.unwrap_or(INLINE_BYTES); 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_decl = quote! { smallvec::SmallVec<#inline_array> };
let sv = 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 { let as_str_impl = match &input.fields {
Fields::Named(_) | Fields::Unit => { 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 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? // FIXME: Remove?
let box_partial_eq_string = expand_partial_eq_string(quote! { Box<#id_ty> }, &impl_generics); 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 owned_decl = expand_owned_id(&input, inline_bytes);
let as_bytes_docs = format!("Creates a byte slice from this `{id}`.");
let max_bytes_docs = format!("Maximum byte length for any `{id}`.");
Ok(quote! { Ok(quote! {
#owned_decl #owned_decl
@ -89,22 +89,27 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[doc = #max_bytes_docs] #[doc = #max_bytes_docs]
pub const MAX_BYTES: usize = ruma_identifiers_validation::MAX_BYTES; pub const MAX_BYTES: usize = ruma_identifiers_validation::MAX_BYTES;
#[inline]
pub(super) const fn from_borrowed(s: &str) -> &Self { pub(super) const fn from_borrowed(s: &str) -> &Self {
unsafe { std::mem::transmute(s) } unsafe { std::mem::transmute(s) }
} }
#[inline]
pub(super) fn from_box(s: Box<str>) -> Box<Self> { pub(super) fn from_box(s: Box<str>) -> Box<Self> {
unsafe { Box::from_raw(Box::into_raw(s) as _) } unsafe { Box::from_raw(Box::into_raw(s) as _) }
} }
#[inline]
pub(super) fn from_rc(s: std::rc::Rc<str>) -> std::rc::Rc<Self> { 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 _) } 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> { 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 _) } unsafe { std::sync::Arc::from_raw(std::sync::Arc::into_raw(s) as _) }
} }
#[inline]
pub(super) fn into_owned(self: Box<Self>) -> #sv_decl { pub(super) fn into_owned(self: Box<Self>) -> #sv_decl {
let len = self.as_bytes().len(); let len = self.as_bytes().len();
let p: *mut u8 = Box::into_raw(self).cast(); 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) #sv::from_vec(v)
} }
#[inline]
pub(super) fn into_box(s: Box<Self>) -> Box<str> { pub(super) fn into_box(s: Box<Self>) -> Box<str> {
unsafe { Box::from_raw(Box::into_raw(s) as _) } 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] #[automatically_derived]
impl #impl_generics AsRef<#id_ty> for #id_ty { impl #impl_generics AsRef<#id_ty> for #id_ty {
#[inline]
fn as_ref(&self) -> &#id_ty { fn as_ref(&self) -> &#id_ty {
self self
} }
@ -154,6 +152,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics AsRef<str> for #id_ty { impl #impl_generics AsRef<str> for #id_ty {
#[inline]
fn as_ref(&self) -> &str { fn as_ref(&self) -> &str {
self.as_str() self.as_str()
} }
@ -161,6 +160,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics AsRef<str> for Box<#id_ty> { impl #impl_generics AsRef<str> for Box<#id_ty> {
#[inline]
fn as_ref(&self) -> &str { fn as_ref(&self) -> &str {
self.as_str() self.as_str()
} }
@ -168,6 +168,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics AsRef<[u8]> for #id_ty { impl #impl_generics AsRef<[u8]> for #id_ty {
#[inline]
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
self.as_bytes() self.as_bytes()
} }
@ -175,11 +176,14 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics AsRef<[u8]> for Box<#id_ty> { impl #impl_generics AsRef<[u8]> for Box<#id_ty> {
#[inline]
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
self.as_bytes() self.as_bytes()
} }
} }
#as_str_impls
#[automatically_derived] #[automatically_derived]
impl #impl_generics From<&#id_ty> for String { impl #impl_generics From<&#id_ty> for String {
fn from(id: &#id_ty) -> Self { fn from(id: &#id_ty) -> Self {
@ -189,6 +193,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics From<Box<#id_ty>> for String { impl #impl_generics From<Box<#id_ty>> for String {
#[inline]
fn from(id: Box<#id_ty>) -> Self { fn from(id: Box<#id_ty>) -> Self {
String::from(<#id_ty>::into_box(id)) String::from(<#id_ty>::into_box(id))
} }
@ -219,6 +224,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<#id_ty> for Box<#id_ty> { impl #impl_generics PartialEq<#id_ty> for Box<#id_ty> {
#[inline]
fn eq(&self, other: &#id_ty) -> bool { fn eq(&self, other: &#id_ty) -> bool {
self.as_str() == other.as_str() self.as_str() == other.as_str()
} }
@ -226,6 +232,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<&'_ #id_ty> for Box<#id_ty> { impl #impl_generics PartialEq<&'_ #id_ty> for Box<#id_ty> {
#[inline]
fn eq(&self, other: &&#id_ty) -> bool { fn eq(&self, other: &&#id_ty) -> bool {
self.as_str() == other.as_str() self.as_str() == other.as_str()
} }
@ -233,6 +240,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<Box<#id_ty>> for #id_ty { impl #impl_generics PartialEq<Box<#id_ty>> for #id_ty {
#[inline]
fn eq(&self, other: &Box<#id_ty>) -> bool { fn eq(&self, other: &Box<#id_ty>) -> bool {
self.as_str() == other.as_str() self.as_str() == other.as_str()
} }
@ -240,13 +248,15 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<Box<#id_ty>> for &'_ #id_ty { impl #impl_generics PartialEq<Box<#id_ty>> for &'_ #id_ty {
#[inline]
fn eq(&self, other: &Box<#id_ty>) -> bool { fn eq(&self, other: &Box<#id_ty>) -> bool {
self.as_str() == other.as_str() self.as_str() == other.as_str()
} }
} }
#as_str_impls #partial_eq_string
#box_partial_eq_string #box_partial_eq_string
#extra_impls #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 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}"); let doc_header = format!("Owned variant of {id}");
@ -300,6 +311,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics AsRef<#id_ty> for #owned_ty { impl #impl_generics AsRef<#id_ty> for #owned_ty {
#[inline]
fn as_ref(&self) -> &#id_ty { fn as_ref(&self) -> &#id_ty {
let s: &str = self.as_ref(); let s: &str = self.as_ref();
<#id_ty>::from_borrowed(s) <#id_ty>::from_borrowed(s)
@ -308,6 +320,15 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics AsRef<str> for #owned_ty { 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 { fn as_ref(&self) -> &str {
let s: &[u8] = self.as_ref(); let s: &[u8] = self.as_ref();
unsafe { std::str::from_utf8_unchecked(s) } unsafe { std::str::from_utf8_unchecked(s) }
@ -316,17 +337,13 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics AsRef<[u8]> for #owned_ty { impl #impl_generics AsRef<[u8]> for #owned_ty {
#[inline]
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
self.inner.as_slice() self.inner.as_slice()
} }
} }
#[automatically_derived] #as_str_impls
impl #impl_generics From<#owned_ty> for String {
fn from(id: #owned_ty) -> String {
unsafe { String::from_utf8_unchecked(id.inner.into_vec()) }
}
}
#[automatically_derived] #[automatically_derived]
impl #impl_generics std::clone::Clone for #owned_ty { 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 { impl #impl_generics std::ops::Deref for #owned_ty {
type Target = #id_ty; type Target = #id_ty;
#[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
self.as_ref() 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] #[automatically_derived]
impl #impl_generics std::borrow::Borrow<#id_ty> for #owned_ty { impl #impl_generics std::borrow::Borrow<#id_ty> for #owned_ty {
#[inline]
fn borrow(&self) -> &#id_ty { fn borrow(&self) -> &#id_ty {
self.as_ref() 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] #[automatically_derived]
impl #impl_generics From<&'_ #id_ty> for #owned_ty { impl #impl_generics From<&'_ #id_ty> for #owned_ty {
fn from(id: &#id_ty) -> #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] #[automatically_derived]
impl #impl_generics From<std::sync::Arc<#id_ty>> for #owned_ty { impl #impl_generics From<std::sync::Arc<#id_ty>> for #owned_ty {
fn from(a: std::sync::Arc<#id_ty>) -> #owned_ty { fn from(id: std::sync::Arc<#id_ty>) -> #owned_ty {
Self::new(a.as_bytes().into()) //TODO (*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] #[automatically_derived]
impl #impl_generics From<#owned_ty> for Box<#id_ty> { impl #impl_generics From<#owned_ty> for Box<#id_ty> {
fn from(a: #owned_ty) -> Box<#id_ty> { fn from(id: #owned_ty) -> Box<#id_ty> {
{ Box::from(<#id_ty>::from_borrowed(a.as_str())) } let id: String = id.into();
let id: Box<str> = id.into_boxed_str();
<#id_ty>::from_box(id)
} }
} }
#[automatically_derived] #[automatically_derived]
impl #impl_generics From<#owned_ty> for std::sync::Arc<#id_ty> { impl #impl_generics From<#owned_ty> for std::sync::Arc<#id_ty> {
fn from(a: #owned_ty) -> std::sync::Arc<#id_ty> { fn from(id: #owned_ty) -> std::sync::Arc<#id_ty> {
{ std::sync::Arc::from(<#id_ty>::from_borrowed(a.as_str())) } let id: Box<#id_ty> = id.into();
} std::sync::Arc::from(id)
}
#[automatically_derived]
impl #impl_generics std::cmp::PartialEq for #owned_ty {
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
} }
} }
#[automatically_derived] #[automatically_derived]
impl #impl_generics std::cmp::Eq for #owned_ty {} 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] #[automatically_derived]
impl #impl_generics std::cmp::PartialOrd for #owned_ty { impl #impl_generics std::cmp::PartialOrd for #owned_ty {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
@ -405,25 +458,15 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics std::cmp::Ord for #owned_ty { impl #impl_generics std::cmp::Ord for #owned_ty {
#[inline]
fn cmp(&self, other: &Self) -> std::cmp::Ordering { fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.as_str().cmp(other.as_str()) 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] #[automatically_derived]
impl #impl_generics PartialEq<#id_ty> for #owned_ty { impl #impl_generics PartialEq<#id_ty> for #owned_ty {
#[inline]
fn eq(&self, other: &#id_ty) -> bool { fn eq(&self, other: &#id_ty) -> bool {
AsRef::<#id_ty>::as_ref(self) == other AsRef::<#id_ty>::as_ref(self) == other
} }
@ -431,6 +474,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<#owned_ty> for #id_ty { impl #impl_generics PartialEq<#owned_ty> for #id_ty {
#[inline]
fn eq(&self, other: &#owned_ty) -> bool { fn eq(&self, other: &#owned_ty) -> bool {
self == AsRef::<#id_ty>::as_ref(other) self == AsRef::<#id_ty>::as_ref(other)
} }
@ -438,6 +482,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<&#id_ty> for #owned_ty { impl #impl_generics PartialEq<&#id_ty> for #owned_ty {
#[inline]
fn eq(&self, other: &&#id_ty) -> bool { fn eq(&self, other: &&#id_ty) -> bool {
AsRef::<#id_ty>::as_ref(self) == *other AsRef::<#id_ty>::as_ref(self) == *other
} }
@ -445,6 +490,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<#owned_ty> for &#id_ty { impl #impl_generics PartialEq<#owned_ty> for &#id_ty {
#[inline]
fn eq(&self, other: &#owned_ty) -> bool { fn eq(&self, other: &#owned_ty) -> bool {
*self == AsRef::<#id_ty>::as_ref(other) *self == AsRef::<#id_ty>::as_ref(other)
} }
@ -452,6 +498,7 @@ fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<Box<#id_ty>> for #owned_ty { impl #impl_generics PartialEq<Box<#id_ty>> for #owned_ty {
#[inline]
fn eq(&self, other: &Box<#id_ty>) -> bool { fn eq(&self, other: &Box<#id_ty>) -> bool {
AsRef::<#id_ty>::as_ref(self) == AsRef::<#id_ty>::as_ref(other) 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] #[automatically_derived]
impl #impl_generics PartialEq<#owned_ty> for Box<#id_ty> { impl #impl_generics PartialEq<#owned_ty> for Box<#id_ty> {
#[inline]
fn eq(&self, other: &#owned_ty) -> bool { fn eq(&self, other: &#owned_ty) -> bool {
AsRef::<#id_ty>::as_ref(self) == AsRef::<#id_ty>::as_ref(other) 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] #[automatically_derived]
impl #impl_generics PartialEq<std::sync::Arc<#id_ty>> for #owned_ty { impl #impl_generics PartialEq<std::sync::Arc<#id_ty>> for #owned_ty {
#[inline]
fn eq(&self, other: &std::sync::Arc<#id_ty>) -> bool { fn eq(&self, other: &std::sync::Arc<#id_ty>) -> bool {
AsRef::<#id_ty>::as_ref(self) == AsRef::<#id_ty>::as_ref(other) 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] #[automatically_derived]
impl #impl_generics PartialEq<#owned_ty> for std::sync::Arc<#id_ty> { impl #impl_generics PartialEq<#owned_ty> for std::sync::Arc<#id_ty> {
#[inline]
fn eq(&self, other: &#owned_ty) -> bool { fn eq(&self, other: &#owned_ty) -> bool {
AsRef::<#id_ty>::as_ref(self) == AsRef::<#id_ty>::as_ref(other) 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}>`."); let parse_arc_docs = format!("Try parsing a `&str` into an `Arc<{id}>`.");
quote! { 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] #[automatically_derived]
impl #impl_generics #id_ty { impl #impl_generics #id_ty {
#[inline] #[inline]
#[doc = #parse_doc_header] #[doc = #parse_doc_header]
/// pub fn parse<S>(s: &S) -> Result<&'_ #id_ty, crate::IdParseError>
/// The same can also be done using `FromStr`, `TryFrom` or `TryInto`. where
/// This function is simply more constrained and thus useful in generic contexts. S: AsRef<str> + ?Sized,
pub fn parse( {
s: impl AsRef<str>, Self::parse_ref(s.as_ref())
) -> Result<#owned_ty, crate::IdParseError> { }
#[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())?; #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] #[inline]
#[doc = #parse_box_doc_header] #[doc = #parse_box_doc_header]
/// fn parse_box(
/// 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(
s: impl AsRef<str> + Into<Box<str>>, s: impl AsRef<str> + Into<Box<str>>,
) -> Result<Box<Self>, crate::IdParseError> { ) -> Result<Box<Self>, crate::IdParseError> {
#validate(s.as_ref())?; #validate(s.as_ref())?;
@ -523,7 +605,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
#[inline] #[inline]
#[doc = #parse_rc_docs] #[doc = #parse_rc_docs]
pub fn parse_rc( fn parse_rc(
s: impl AsRef<str> + Into<std::rc::Rc<str>>, s: impl AsRef<str> + Into<std::rc::Rc<str>>,
) -> Result<std::rc::Rc<Self>, crate::IdParseError> { ) -> Result<std::rc::Rc<Self>, crate::IdParseError> {
#validate(s.as_ref())?; #validate(s.as_ref())?;
@ -532,7 +614,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
#[inline] #[inline]
#[doc = #parse_arc_docs] #[doc = #parse_arc_docs]
pub fn parse_arc( fn parse_arc(
s: impl AsRef<str> + Into<std::sync::Arc<str>>, s: impl AsRef<str> + Into<std::sync::Arc<str>>,
) -> Result<std::sync::Arc<Self>, crate::IdParseError> { ) -> Result<std::sync::Arc<Self>, crate::IdParseError> {
#validate(s.as_ref())?; #validate(s.as_ref())?;
@ -541,18 +623,18 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
} }
#[automatically_derived] #[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> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
use serde::de::Error; use serde::de::Error;
let s = String::deserialize(deserializer)?; let s = <&'de str>::deserialize(deserializer)?;
match <#id_ty>::parse_box(s) { match <#id_ty>::parse_ref(s) {
Ok(o) => Ok(o),
Err(e) => Err(D::Error::custom(e)), 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)?; let s = String::deserialize(deserializer)?;
match <#id_ty>::parse(s) { match <#id_ty>::parse_into_owned(s) {
Ok(o) => Ok(o),
Err(e) => Err(D::Error::custom(e)), Err(e) => Err(D::Error::custom(e)),
Ok(o) => Ok(o),
} }
} }
} }
#[automatically_derived] #[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> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
use serde::de::Error; use serde::de::Error;
let s = <&'de str>::deserialize(deserializer)?; let s = Box::<str>::deserialize(deserializer)?;
match #validate(s) { match <#id_ty>::parse_box(s) {
Ok(_) => Ok(<#id_ty>::from_borrowed(s)),
Err(e) => Err(D::Error::custom(e)), 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 { impl<'a, #generic_params> std::convert::TryFrom<&'a str> for &'a #id_ty {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> { fn try_from(s: &'a str) -> Result<Self, Self::Error> {
#validate(s)?; #validate(s)?;
Ok(<#id_ty>::from_borrowed(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 { impl<'a, #generic_params> std::convert::TryFrom<&'a serde_json::Value> for &'a #id_ty {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(v: &'a serde_json::Value) -> Result<Self, Self::Error> { 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 { impl<'a, #generic_params> std::convert::TryFrom<&'a crate::CanonicalJsonValue> for &'a #id_ty {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(v: &'a crate::CanonicalJsonValue) -> Result<Self, Self::Error> { 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 { impl<'a, #generic_params> std::convert::TryFrom<Option<&'a serde_json::Value>> for &'a #id_ty {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(v: Option<&'a serde_json::Value>) -> Result<Self, Self::Error> { 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 { impl<'a, #generic_params> std::convert::TryFrom<Option<&'a crate::CanonicalJsonValue>> for &'a #id_ty {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(v: Option<&'a crate::CanonicalJsonValue>) -> Result<Self, Self::Error> { 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> { impl #impl_generics std::str::FromStr for Box<#id_ty> {
type Err = crate::IdParseError; type Err = crate::IdParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
<#id_ty>::parse_box(s) <#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> { impl #impl_generics std::convert::TryFrom<&str> for Box<#id_ty> {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(s: &str) -> Result<Self, Self::Error> { fn try_from(s: &str) -> Result<Self, Self::Error> {
<#id_ty>::parse_box(s) <#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> { impl #impl_generics std::convert::TryFrom<String> for Box<#id_ty> {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> { fn try_from(s: String) -> Result<Self, Self::Error> {
<#id_ty>::parse_box(s.into_boxed_str()) <#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 { impl #impl_generics std::str::FromStr for #owned_ty {
type Err = crate::IdParseError; type Err = crate::IdParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
<#id_ty>::parse(s) <#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 { impl #impl_generics std::convert::TryFrom<&str> for #owned_ty {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(s: &str) -> Result<Self, Self::Error> { 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 { impl #impl_generics std::convert::TryFrom<String> for #owned_ty {
type Error = crate::IdParseError; type Error = crate::IdParseError;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> { 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! { quote! {
#[automatically_derived] #[automatically_derived]
impl<'a, #generic_params> From<&'a str> for &'a #id_ty { impl<'a, #generic_params> From<&'a str> for &'a #id_ty {
#[inline]
fn from(s: &'a str) -> Self { fn from(s: &'a str) -> Self {
<#id_ty>::from_borrowed(s) <#id_ty>::from_borrowed(s)
} }
@ -714,6 +808,7 @@ fn expand_unchecked_impls(input: &ItemStruct) -> TokenStream {
#[automatically_derived] #[automatically_derived]
impl #impl_generics From<&str> for #owned_ty { impl #impl_generics From<&str> for #owned_ty {
#[inline]
fn from(s: &str) -> Self { fn from(s: &str) -> Self {
<&#id_ty>::from(s).into() <&#id_ty>::from(s).into()
} }
@ -764,12 +859,12 @@ fn expand_unchecked_impls(input: &ItemStruct) -> TokenStream {
} }
#[automatically_derived] #[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> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de>, 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 where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
// FIXME: Deserialize inner, convert that
Box::<str>::deserialize(deserializer).map(<#id_ty>::from_box).map(Into::into) Box::<str>::deserialize(deserializer).map(<#id_ty>::from_box).map(Into::into)
} }
} }
#[automatically_derived] #[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> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de>, 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 { fn expand_as_str_impls(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -> TokenStream {
let partial_eq_string = expand_partial_eq_string(ty.clone(), impl_generics);
quote! { quote! {
#[automatically_derived] #[automatically_derived]
impl #impl_generics std::fmt::Display for #ty { impl #impl_generics std::fmt::Display for #ty {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str()) write!(f, "{}", self.as_str())
} }
@ -809,6 +902,7 @@ fn expand_as_str_impls(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -> Tok
#[automatically_derived] #[automatically_derived]
impl #impl_generics std::fmt::Debug for #ty { impl #impl_generics std::fmt::Debug for #ty {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<str as std::fmt::Debug>::fmt(self.as_str(), f) <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()) serializer.serialize_str(self.as_str())
} }
} }
#partial_eq_string
} }
} }
@ -841,6 +933,7 @@ fn expand_partial_eq_string(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -
quote! { quote! {
#[automatically_derived] #[automatically_derived]
impl #impl_generics PartialEq<#rhs> for #lhs { impl #impl_generics PartialEq<#rhs> for #lhs {
#[inline]
fn eq(&self, other: &#rhs) -> bool { fn eq(&self, other: &#rhs) -> bool {
AsRef::<str>::as_ref(self) == AsRef::<str>::as_ref(other) AsRef::<str>::as_ref(self) == AsRef::<str>::as_ref(other)
} }