macros: Expand IdZst derive to generic types
… and use it for KeyId.
This commit is contained in:
parent
5d8f6748e6
commit
ae095cc037
@ -1,18 +1,18 @@
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
convert::TryFrom,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
rc::Rc,
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use super::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, IdParseError, KeyName};
|
||||
use ruma_macros::IdZst;
|
||||
|
||||
use super::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName};
|
||||
|
||||
/// A key algorithm and key name delimited by a colon.
|
||||
#[repr(transparent)]
|
||||
#[derive(IdZst)]
|
||||
#[ruma_id(validate = ruma_identifiers_validation::key_id::validate)]
|
||||
pub struct KeyId<A, K: ?Sized>(PhantomData<(A, K)>, str);
|
||||
|
||||
impl<A, K: ?Sized> KeyId<A, K> {
|
||||
@ -49,28 +49,6 @@ impl<A, K: ?Sized> KeyId<A, K> {
|
||||
self.as_str()[self.colon_idx() + 1..].into()
|
||||
}
|
||||
|
||||
/// Creates a string slice from this `KeyId`.
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.1
|
||||
}
|
||||
|
||||
/// Creates a byte slice from this `KeyId`.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
self.1.as_bytes()
|
||||
}
|
||||
|
||||
fn from_borrowed(s: &str) -> &Self {
|
||||
unsafe { std::mem::transmute(s) }
|
||||
}
|
||||
|
||||
fn from_box(s: Box<str>) -> Box<Self> {
|
||||
unsafe { Box::from_raw(Box::into_raw(s) as _) }
|
||||
}
|
||||
|
||||
fn into_owned(self: Box<Self>) -> Box<str> {
|
||||
unsafe { Box::from_raw(Box::into_raw(self) as _) }
|
||||
}
|
||||
|
||||
fn colon_idx(&self) -> usize {
|
||||
self.as_str().find(':').unwrap()
|
||||
}
|
||||
@ -85,88 +63,8 @@ pub type ServerSigningKeyId = SigningKeyId<KeyName>;
|
||||
/// Algorithm + key name for device keys.
|
||||
pub type DeviceSigningKeyId = SigningKeyId<DeviceId>;
|
||||
|
||||
impl<A, K: ?Sized> Clone for Box<KeyId<A, K>> {
|
||||
fn clone(&self) -> Self {
|
||||
(**self).to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> ToOwned for KeyId<A, K> {
|
||||
type Owned = Box<KeyId<A, K>>;
|
||||
|
||||
fn to_owned(&self) -> Self::Owned {
|
||||
Self::from_box(self.1.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> From<&KeyId<A, K>> for Box<KeyId<A, K>> {
|
||||
fn from(id: &KeyId<A, K>) -> Self {
|
||||
id.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> AsRef<str> for Box<KeyId<A, K>> {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> From<&KeyId<A, K>> for Rc<KeyId<A, K>> {
|
||||
fn from(s: &KeyId<A, K>) -> Rc<KeyId<A, K>> {
|
||||
let rc = Rc::<str>::from(s.as_str());
|
||||
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const KeyId<A, K>) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> From<&KeyId<A, K>> for Arc<KeyId<A, K>> {
|
||||
fn from(s: &KeyId<A, K>) -> Arc<KeyId<A, K>> {
|
||||
let arc = Arc::<str>::from(s.as_str());
|
||||
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const KeyId<A, K>) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> PartialEq<KeyId<A, K>> for Box<KeyId<A, K>> {
|
||||
fn eq(&self, other: &KeyId<A, K>) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> PartialEq<&'_ KeyId<A, K>> for Box<KeyId<A, K>> {
|
||||
fn eq(&self, other: &&KeyId<A, K>) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> PartialEq<Box<KeyId<A, K>>> for KeyId<A, K> {
|
||||
fn eq(&self, other: &Box<KeyId<A, K>>) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> PartialEq<Box<KeyId<A, K>>> for &'_ KeyId<A, K> {
|
||||
fn eq(&self, other: &Box<KeyId<A, K>>) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> AsRef<str> for KeyId<A, K> {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> fmt::Display for KeyId<A, K> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.as_str().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> fmt::Debug for KeyId<A, K> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.as_str().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
// The following impls are usually derived using the std macros.
|
||||
// They are implemented manually here to avoid unnecessary bounds.
|
||||
impl<A, K: ?Sized> PartialEq for KeyId<A, K> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
@ -192,95 +90,3 @@ impl<A, K: ?Sized> Hash for KeyId<A, K> {
|
||||
self.as_str().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> serde::Serialize for KeyId<A, K> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> From<Box<KeyId<A, K>>> for String {
|
||||
fn from(id: Box<KeyId<A, K>>) -> Self {
|
||||
id.into_owned().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, A, K: ?Sized> serde::Deserialize<'de> for Box<KeyId<A, K>> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
use serde::de::Error;
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match try_from(s) {
|
||||
Ok(o) => Ok(o),
|
||||
Err(e) => Err(D::Error::custom(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_from<S, A, K: ?Sized>(s: S) -> Result<Box<KeyId<A, K>>, IdParseError>
|
||||
where
|
||||
S: AsRef<str> + Into<Box<str>>,
|
||||
{
|
||||
ruma_identifiers_validation::key_id::validate(s.as_ref())?;
|
||||
Ok(KeyId::from_box(s.into()))
|
||||
}
|
||||
|
||||
impl<'a, A, K: ?Sized> TryFrom<&'a str> for &'a KeyId<A, K> {
|
||||
type Error = IdParseError;
|
||||
|
||||
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||
(ruma_identifiers_validation::key_id::validate)(s)?;
|
||||
Ok(KeyId::from_borrowed(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> FromStr for Box<KeyId<A, K>> {
|
||||
type Err = IdParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> TryFrom<&str> for Box<KeyId<A, K>> {
|
||||
type Error = IdParseError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> TryFrom<String> for Box<KeyId<A, K>> {
|
||||
type Error = IdParseError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! partial_eq_string {
|
||||
($id:ty $([$( $g:ident ),*])?) => {
|
||||
partial_eq_string!(@imp $(<$($g),*>)?, $id, str);
|
||||
partial_eq_string!(@imp $(<$($g),*>)?, $id, &str);
|
||||
partial_eq_string!(@imp $(<$($g),*>)?, $id, String);
|
||||
partial_eq_string!(@imp $(<$($g),*>)?, str, $id);
|
||||
partial_eq_string!(@imp $(<$($g),*>)?, &str, $id);
|
||||
partial_eq_string!(@imp $(<$($g),*>)?, String, $id);
|
||||
};
|
||||
(@imp $(<$( $g:ident ),*>)?, $l:ty, $r:ty) => {
|
||||
impl $(<$($g),*>)? PartialEq<$r> for $l {
|
||||
fn eq(&self, other: &$r) -> bool {
|
||||
AsRef::<str>::as_ref(self)
|
||||
== AsRef::<str>::as_ref(other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
partial_eq_string!(KeyId<A, K> [A, K]);
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! Methods and types for generating identifiers.
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
punctuated::Punctuated,
|
||||
Ident, ItemStruct, LitStr, Path, Token,
|
||||
Fields, ImplGenerics, Index, ItemStruct, LitStr, Path, Token,
|
||||
};
|
||||
|
||||
pub struct IdentifierInput {
|
||||
@ -25,9 +25,8 @@ impl Parse for IdentifierInput {
|
||||
|
||||
pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
let id = &input.ident;
|
||||
let owned = format_ident!("Owned{}", id);
|
||||
|
||||
let owned_decl = expand_owned_id(id, &owned);
|
||||
let owned_decl = expand_owned_id(&input);
|
||||
|
||||
let meta = input.attrs.iter().filter(|attr| attr.path.is_ident("ruma_id")).try_fold(
|
||||
IdZstMeta::default(),
|
||||
@ -40,22 +39,42 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
)?;
|
||||
|
||||
let extra_impls = if let Some(validate) = meta.validate {
|
||||
expand_checked_impls(id, &owned, validate)
|
||||
expand_checked_impls(&input, validate)
|
||||
} else {
|
||||
expand_unchecked_impls(id, &owned)
|
||||
assert!(
|
||||
input.generics.params.is_empty(),
|
||||
"generic unchecked IDs are not currently supported"
|
||||
);
|
||||
expand_unchecked_impls(&input)
|
||||
};
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
// So we don't have to insert #where_clause everywhere when it is always None in practice
|
||||
assert_eq!(where_clause, None, "where clauses on identifier types are not currently supported");
|
||||
|
||||
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 partial_eq_string = expand_partial_eq_string(id);
|
||||
let as_str_impl = match &input.fields {
|
||||
Fields::Named(_) | Fields::Unit => {
|
||||
syn::Error::new(Span::call_site(), "Only tuple structs are supported currently.")
|
||||
.into_compile_error()
|
||||
}
|
||||
Fields::Unnamed(u) => {
|
||||
let last_idx = Index::from(u.unnamed.len() - 1);
|
||||
quote! { &self.#last_idx }
|
||||
}
|
||||
};
|
||||
|
||||
let partial_eq_string = expand_partial_eq_string(quote! { #id #ty_generics }, &impl_generics);
|
||||
// FIXME: Remove?
|
||||
let box_partial_eq_string = expand_partial_eq_string(quote! { Box<#id> });
|
||||
let box_partial_eq_string =
|
||||
expand_partial_eq_string(quote! { Box<#id #ty_generics> }, &impl_generics);
|
||||
|
||||
Ok(quote! {
|
||||
#owned_decl
|
||||
|
||||
impl #id {
|
||||
impl #impl_generics #id #ty_generics {
|
||||
pub(super) fn from_borrowed(s: &str) -> &Self {
|
||||
unsafe { std::mem::transmute(s) }
|
||||
}
|
||||
@ -77,111 +96,113 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
}
|
||||
|
||||
#[doc = #as_str_docs]
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> &str {
|
||||
&self.0
|
||||
#as_str_impl
|
||||
}
|
||||
|
||||
#[doc = #as_bytes_docs]
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
self.0.as_bytes()
|
||||
self.as_str().as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<#id> {
|
||||
impl #impl_generics Clone for Box<#id #ty_generics> {
|
||||
fn clone(&self) -> Self {
|
||||
(**self).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToOwned for #id {
|
||||
type Owned = Box<#id>;
|
||||
impl #impl_generics ToOwned for #id #ty_generics {
|
||||
type Owned = Box<#id #ty_generics>;
|
||||
|
||||
fn to_owned(&self) -> Self::Owned {
|
||||
Self::from_box(self.0.into())
|
||||
Self::from_box(self.as_str().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for #id {
|
||||
impl #impl_generics AsRef<str> for #id #ty_generics {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Box<#id> {
|
||||
impl #impl_generics AsRef<str> for Box<#id #ty_generics> {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&#id> for String {
|
||||
fn from(id: &#id) -> Self {
|
||||
impl #impl_generics From<&#id #ty_generics> for String {
|
||||
fn from(id: &#id #ty_generics) -> Self {
|
||||
id.as_str().to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<#id>> for String {
|
||||
fn from(id: Box<#id>) -> Self {
|
||||
impl #impl_generics From<Box<#id #ty_generics>> for String {
|
||||
fn from(id: Box<#id #ty_generics>) -> Self {
|
||||
id.into_owned().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&#id> for Box<#id> {
|
||||
fn from(id: &#id) -> Self {
|
||||
#id::from_box(id.0.into())
|
||||
impl #impl_generics From<&#id #ty_generics> for Box<#id #ty_generics> {
|
||||
fn from(id: &#id #ty_generics) -> Self {
|
||||
<#id #ty_generics>::from_box(id.as_str().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&#id> for std::rc::Rc<#id> {
|
||||
fn from(s: &#id) -> std::rc::Rc<#id> {
|
||||
impl #impl_generics From<&#id #ty_generics> for std::rc::Rc<#id #ty_generics> {
|
||||
fn from(s: &#id #ty_generics) -> std::rc::Rc<#id #ty_generics> {
|
||||
let rc = std::rc::Rc::<str>::from(s.as_str());
|
||||
<#id>::from_rc(rc)
|
||||
<#id #ty_generics>::from_rc(rc)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&#id> for std::sync::Arc<#id> {
|
||||
fn from(s: &#id) -> std::sync::Arc<#id> {
|
||||
impl #impl_generics From<&#id #ty_generics> for std::sync::Arc<#id #ty_generics> {
|
||||
fn from(s: &#id #ty_generics) -> std::sync::Arc<#id #ty_generics> {
|
||||
let arc = std::sync::Arc::<str>::from(s.as_str());
|
||||
<#id>::from_arc(arc)
|
||||
<#id #ty_generics>::from_arc(arc)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<#id> for Box<#id> {
|
||||
fn eq(&self, other: &#id) -> bool {
|
||||
impl #impl_generics PartialEq<#id #ty_generics> for Box<#id #ty_generics> {
|
||||
fn eq(&self, other: &#id #ty_generics) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ #id> for Box<#id> {
|
||||
fn eq(&self, other: &&#id) -> bool {
|
||||
impl #impl_generics PartialEq<&'_ #id #ty_generics> for Box<#id #ty_generics> {
|
||||
fn eq(&self, other: &&#id #ty_generics) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Box<#id>> for #id {
|
||||
fn eq(&self, other: &Box<#id>) -> bool {
|
||||
impl #impl_generics PartialEq<Box<#id #ty_generics>> for #id #ty_generics {
|
||||
fn eq(&self, other: &Box<#id #ty_generics>) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Box<#id>> for &'_ #id {
|
||||
fn eq(&self, other: &Box<#id>) -> bool {
|
||||
impl #impl_generics PartialEq<Box<#id #ty_generics>> for &'_ #id #ty_generics {
|
||||
fn eq(&self, other: &Box<#id #ty_generics>) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for #id {
|
||||
impl #impl_generics std::fmt::Debug for #id #ty_generics {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
<str as std::fmt::Debug>::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for #id {
|
||||
impl #impl_generics std::fmt::Display for #id #ty_generics {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for #id {
|
||||
impl #impl_generics serde::Serialize for #id #ty_generics {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
@ -196,9 +217,14 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
})
|
||||
}
|
||||
|
||||
fn expand_owned_id(id: &Ident, owned: &Ident) -> TokenStream {
|
||||
fn expand_owned_id(input: &ItemStruct) -> TokenStream {
|
||||
let id = &input.ident;
|
||||
let owned = format_ident!("Owned{}", id);
|
||||
|
||||
let doc_header = format!("Owned variant of {}", id);
|
||||
let partial_eq_string = expand_partial_eq_string(owned);
|
||||
let (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl();
|
||||
let partial_eq_string =
|
||||
expand_partial_eq_string(quote! { #owned #ty_generics }, &impl_generics);
|
||||
|
||||
quote! {
|
||||
#[doc = #doc_header]
|
||||
@ -209,53 +235,53 @@ fn expand_owned_id(id: &Ident, owned: &Ident) -> TokenStream {
|
||||
/// to the following;
|
||||
/// - `ruma_identifiers_storage="Arc"` to use [`Arc`](std::sync::Arc) as a wrapper type.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct #owned {
|
||||
pub struct #owned #impl_generics {
|
||||
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
|
||||
inner: Box<#id>,
|
||||
inner: Box<#id #ty_generics>,
|
||||
#[cfg(ruma_identifiers_storage = "Arc")]
|
||||
inner: std::sync::Arc<#id>,
|
||||
inner: std::sync::Arc<#id #ty_generics>,
|
||||
}
|
||||
|
||||
impl AsRef<#id> for #owned {
|
||||
fn as_ref(&self) -> &#id {
|
||||
impl #impl_generics AsRef<#id #ty_generics> for #owned #ty_generics {
|
||||
fn as_ref(&self) -> &#id #ty_generics {
|
||||
&*self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for #owned {
|
||||
impl #impl_generics AsRef<str> for #owned #ty_generics {
|
||||
fn as_ref(&self) -> &str {
|
||||
(*self.inner).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for #owned {
|
||||
type Target = #id;
|
||||
impl #impl_generics std::ops::Deref for #owned #ty_generics {
|
||||
type Target = #id #ty_generics;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<#id> for #owned {
|
||||
fn borrow(&self) -> &#id {
|
||||
impl #impl_generics std::borrow::Borrow<#id #ty_generics> for #owned #ty_generics {
|
||||
fn borrow(&self) -> &#id #ty_generics {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ #id> for #owned {
|
||||
fn from(id: &#id) -> #owned {
|
||||
impl #impl_generics From<&'_ #id #ty_generics> for #owned #ty_generics {
|
||||
fn from(id: &#id #ty_generics) -> #owned #ty_generics {
|
||||
#owned { inner: id.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<#id>> for #owned {
|
||||
fn from(b: Box<#id>) -> #owned {
|
||||
impl #impl_generics From<Box<#id #ty_generics>> for #owned #ty_generics {
|
||||
fn from(b: Box<#id #ty_generics>) -> #owned #ty_generics {
|
||||
Self { inner: b.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::sync::Arc<#id>> for #owned {
|
||||
fn from(a: std::sync::Arc<#id>) -> #owned {
|
||||
impl #impl_generics From<std::sync::Arc<#id #ty_generics>> for #owned #ty_generics {
|
||||
fn from(a: std::sync::Arc<#id #ty_generics>) -> #owned #ty_generics {
|
||||
Self {
|
||||
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
|
||||
inner: a.as_ref().into(),
|
||||
@ -265,13 +291,13 @@ fn expand_owned_id(id: &Ident, owned: &Ident) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for #owned {
|
||||
impl #impl_generics std::fmt::Display for #owned #ty_generics {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for #owned {
|
||||
impl #impl_generics serde::Serialize for #owned #ty_generics {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
@ -282,51 +308,57 @@ fn expand_owned_id(id: &Ident, owned: &Ident) -> TokenStream {
|
||||
|
||||
#partial_eq_string
|
||||
|
||||
impl PartialEq<#id> for #owned {
|
||||
fn eq(&self, other: &#id) -> bool {
|
||||
AsRef::<#id>::as_ref(self) == other
|
||||
impl #impl_generics PartialEq<#id #ty_generics> for #owned #ty_generics {
|
||||
fn eq(&self, other: &#id #ty_generics) -> bool {
|
||||
AsRef::<#id #ty_generics>::as_ref(self) == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<#owned> for #id {
|
||||
fn eq(&self, other: &#owned) -> bool {
|
||||
self == AsRef::<#id>::as_ref(other)
|
||||
impl #impl_generics PartialEq<#owned #ty_generics> for #id #ty_generics {
|
||||
fn eq(&self, other: &#owned #ty_generics) -> bool {
|
||||
self == AsRef::<#id #ty_generics>::as_ref(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&#id> for #owned {
|
||||
fn eq(&self, other: &&#id) -> bool {
|
||||
AsRef::<#id>::as_ref(self) == *other
|
||||
impl #impl_generics PartialEq<&#id #ty_generics> for #owned #ty_generics {
|
||||
fn eq(&self, other: &&#id #ty_generics) -> bool {
|
||||
AsRef::<#id #ty_generics>::as_ref(self) == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<#owned> for &#id {
|
||||
fn eq(&self, other: &#owned) -> bool {
|
||||
*self == AsRef::<#id>::as_ref(other)
|
||||
impl #impl_generics PartialEq<#owned #ty_generics> for &#id #ty_generics {
|
||||
fn eq(&self, other: &#owned #ty_generics) -> bool {
|
||||
*self == AsRef::<#id #ty_generics>::as_ref(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Box<#id>> for #owned {
|
||||
fn eq(&self, other: &Box<#id>) -> bool {
|
||||
AsRef::<#id>::as_ref(self) == AsRef::<#id>::as_ref(other)
|
||||
impl #impl_generics PartialEq<Box<#id #ty_generics>> for #owned #ty_generics {
|
||||
fn eq(&self, other: &Box<#id #ty_generics>) -> bool {
|
||||
AsRef::<#id #ty_generics>::as_ref(self) == AsRef::<#id #ty_generics>::as_ref(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<#owned> for Box<#id> {
|
||||
fn eq(&self, other: &#owned) -> bool {
|
||||
AsRef::<#id>::as_ref(self) == AsRef::<#id>::as_ref(other)
|
||||
impl #impl_generics PartialEq<#owned #ty_generics> for Box<#id #ty_generics> {
|
||||
fn eq(&self, other: &#owned #ty_generics) -> bool {
|
||||
AsRef::<#id #ty_generics>::as_ref(self) == AsRef::<#id #ty_generics>::as_ref(other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_checked_impls(id: &Ident, owned: &Ident, validate: Path) -> TokenStream {
|
||||
fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
let id = &input.ident;
|
||||
let owned = format_ident!("Owned{}", id);
|
||||
|
||||
let (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl();
|
||||
let generic_params = &input.generics.params;
|
||||
|
||||
let parse_doc_header = format!("Try parsing a `&str` into a `Box<{}>`.", id);
|
||||
let parse_rc_docs = format!("Try parsing a `&str` into an `Rc<{}>`.", id);
|
||||
let parse_arc_docs = format!("Try parsing a `&str` into an `Arc<{}>`.", id);
|
||||
|
||||
quote! {
|
||||
impl #id {
|
||||
impl #impl_generics #id #ty_generics {
|
||||
#[doc = #parse_doc_header]
|
||||
///
|
||||
/// The same can also be done using `FromStr`, `TryFrom` or `TryInto`.
|
||||
@ -355,7 +387,7 @@ fn expand_checked_impls(id: &Ident, owned: &Ident, validate: Path) -> TokenStrea
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for Box<#id> {
|
||||
impl<'de, #generic_params> serde::Deserialize<'de> for Box<#id #ty_generics> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
@ -371,7 +403,7 @@ fn expand_checked_impls(id: &Ident, owned: &Ident, validate: Path) -> TokenStrea
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for #owned {
|
||||
impl<'de, #generic_params> serde::Deserialize<'de> for #owned #ty_generics {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
@ -387,42 +419,45 @@ fn expand_checked_impls(id: &Ident, owned: &Ident, validate: Path) -> TokenStrea
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::convert::TryFrom<&'a str> for &'a #id {
|
||||
impl<'a, #generic_params> std::convert::TryFrom<&'a str> for &'a #id #ty_generics {
|
||||
type Error = crate::IdParseError;
|
||||
|
||||
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||
#validate(s)?;
|
||||
Ok(#id::from_borrowed(s))
|
||||
Ok(<#id #ty_generics>::from_borrowed(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for Box<#id> {
|
||||
impl #impl_generics std::str::FromStr for Box<#id #ty_generics> {
|
||||
type Err = crate::IdParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
#id::parse(s)
|
||||
<#id #ty_generics>::parse(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for Box<#id> {
|
||||
impl #impl_generics std::convert::TryFrom<&str> for Box<#id #ty_generics> {
|
||||
type Error = crate::IdParseError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
#id::parse(s)
|
||||
<#id #ty_generics>::parse(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<String> for Box<#id> {
|
||||
impl #impl_generics std::convert::TryFrom<String> for Box<#id #ty_generics> {
|
||||
type Error = crate::IdParseError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
#id::parse(s)
|
||||
<#id #ty_generics>::parse(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_unchecked_impls(id: &Ident, owned: &Ident) -> TokenStream {
|
||||
fn expand_unchecked_impls(input: &ItemStruct) -> TokenStream {
|
||||
let id = &input.ident;
|
||||
let owned = format_ident!("Owned{}", id);
|
||||
|
||||
quote! {
|
||||
impl<'a> From<&'a str> for &'a #id {
|
||||
fn from(s: &'a str) -> Self {
|
||||
@ -475,28 +510,26 @@ fn expand_unchecked_impls(id: &Ident, owned: &Ident) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_partial_eq_string(id: impl ToTokens) -> TokenStream {
|
||||
fn single_impl(lhs: impl ToTokens, rhs: impl ToTokens) -> TokenStream {
|
||||
fn expand_partial_eq_string(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -> TokenStream {
|
||||
IntoIterator::into_iter([
|
||||
(ty.clone(), quote! { str }),
|
||||
(ty.clone(), quote! { &str }),
|
||||
(ty.clone(), quote! { String }),
|
||||
(quote! { str }, ty.clone()),
|
||||
(quote! { &str }, ty.clone()),
|
||||
(quote! { String }, ty),
|
||||
])
|
||||
.map(|(lhs, rhs)| {
|
||||
quote! {
|
||||
impl PartialEq<#rhs> for #lhs {
|
||||
impl #impl_generics PartialEq<#rhs> for #lhs {
|
||||
fn eq(&self, other: &#rhs) -> bool {
|
||||
AsRef::<str>::as_ref(self)
|
||||
== AsRef::<str>::as_ref(other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let id = &id;
|
||||
|
||||
let mut res = TokenStream::new();
|
||||
res.extend(single_impl(id, quote! { str }));
|
||||
res.extend(single_impl(id, quote! { &str }));
|
||||
res.extend(single_impl(id, quote! { String }));
|
||||
res.extend(single_impl(quote! { str }, id));
|
||||
res.extend(single_impl(quote! { &str }, id));
|
||||
res.extend(single_impl(quote! { String }, id));
|
||||
res
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
mod kw {
|
||||
|
Loading…
x
Reference in New Issue
Block a user