refactor owned identifiers using SmallVec
This commit is contained in:
parent
d3ed3194eb
commit
54da128bbe
@ -35,6 +35,7 @@ ruma-state-res = { version = "0.11.0", path = "crates/ruma-state-res" }
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
serde_html_form = "0.2.0"
|
||||
serde_json = "1.0.87"
|
||||
smallvec = { version = "1.13.2", features = ["const_generics", "const_new", "serde", "union", "write"] }
|
||||
thiserror = "2.0.0"
|
||||
tracing = { version = "0.1.37", default-features = false, features = ["std"] }
|
||||
url = { version = "2.5.0" }
|
||||
|
@ -79,6 +79,7 @@ ruma-macros = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_html_form = { workspace = true }
|
||||
serde_json = { workspace = true, features = ["raw_value"] }
|
||||
smallvec = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
time = "0.3.34"
|
||||
tracing = { workspace = true, features = ["attributes"] }
|
||||
|
@ -37,7 +37,10 @@ use super::ServerName;
|
||||
/// [room versions]: https://spec.matrix.org/latest/rooms/#complete-list-of-room-versions
|
||||
#[repr(transparent)]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)]
|
||||
#[ruma_id(validate = ruma_identifiers_validation::event_id::validate)]
|
||||
#[ruma_id(
|
||||
validate = ruma_identifiers_validation::event_id::validate,
|
||||
inline_bytes = 48
|
||||
)]
|
||||
pub struct EventId(str);
|
||||
|
||||
impl EventId {
|
||||
|
@ -75,6 +75,7 @@ ruma-identifiers-validation = { workspace = true }
|
||||
ruma-macros = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true, features = ["raw_value"] }
|
||||
smallvec = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true, features = ["attributes"] }
|
||||
url = { workspace = true }
|
||||
|
@ -24,11 +24,6 @@ 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(&input);
|
||||
|
||||
let meta = input.attrs.iter().filter(|attr| attr.path().is_ident("ruma_id")).try_fold(
|
||||
IdZstMeta::default(),
|
||||
|meta, attr| {
|
||||
@ -53,9 +48,18 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
// 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 max_bytes_docs = format!("Maximum byte length for any `{id}`.");
|
||||
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);
|
||||
let inline_array = quote! { [u8; #inline_bytes] };
|
||||
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_impl = match &input.fields {
|
||||
Fields::Named(_) | Fields::Unit => {
|
||||
@ -68,13 +72,14 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
}
|
||||
};
|
||||
|
||||
let id_ty = quote! { #id #ty_generics };
|
||||
let owned_ty = quote! { #owned #ty_generics };
|
||||
|
||||
let as_str_impls = expand_as_str_impls(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}`.");
|
||||
|
||||
Ok(quote! {
|
||||
#owned_decl
|
||||
|
||||
@ -100,8 +105,15 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
unsafe { std::sync::Arc::from_raw(std::sync::Arc::into_raw(s) as _) }
|
||||
}
|
||||
|
||||
pub(super) fn into_owned(self: Box<Self>) -> Box<str> {
|
||||
unsafe { Box::from_raw(Box::into_raw(self) as _) }
|
||||
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();
|
||||
let v = unsafe { Vec::<u8>::from_raw_parts(p, len, len) };
|
||||
#sv::from_vec(v)
|
||||
}
|
||||
|
||||
pub(super) fn into_box(s: Box<Self>) -> Box<str> {
|
||||
unsafe { Box::from_raw(Box::into_raw(s) as _) }
|
||||
}
|
||||
|
||||
#[doc = #as_str_docs]
|
||||
@ -129,7 +141,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
type Owned = #owned_ty;
|
||||
|
||||
fn to_owned(&self) -> Self::Owned {
|
||||
#owned::from_ref(self)
|
||||
Self::Owned::new(self.as_bytes().into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +190,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics From<Box<#id_ty>> for String {
|
||||
fn from(id: Box<#id_ty>) -> Self {
|
||||
id.into_owned().into()
|
||||
String::from(<#id_ty>::into_box(id))
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,41 +251,49 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> {
|
||||
})
|
||||
}
|
||||
|
||||
fn expand_owned_id(input: &ItemStruct) -> TokenStream {
|
||||
fn expand_owned_id(input: &ItemStruct, inline_bytes: usize) -> TokenStream {
|
||||
let (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl();
|
||||
let listed_generics: Punctuated<_, Token![,]> =
|
||||
input.generics.type_params().map(|param| ¶m.ident).collect();
|
||||
|
||||
let id = &input.ident;
|
||||
let owned = format_ident!("Owned{id}");
|
||||
|
||||
let doc_header = format!("Owned variant of {id}");
|
||||
let (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl();
|
||||
|
||||
let id_ty = quote! { #id #ty_generics };
|
||||
let owned_ty = quote! { #owned #ty_generics };
|
||||
|
||||
let inline_array = quote! { [u8; #inline_bytes] };
|
||||
let sv_decl = quote! { smallvec::SmallVec<#inline_array> };
|
||||
|
||||
let has_generics = !listed_generics.is_empty();
|
||||
let phantom_decl = if has_generics {
|
||||
quote! { _p: std::marker::PhantomData<(#listed_generics)>, }
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let phantom_impl = if has_generics {
|
||||
quote! { _p: std::marker::PhantomData::<(#listed_generics)>, }
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let as_str_impls = expand_as_str_impls(owned_ty.clone(), &impl_generics);
|
||||
|
||||
let doc_header = format!("Owned variant of {id}");
|
||||
|
||||
quote! {
|
||||
#[doc = #doc_header]
|
||||
///
|
||||
/// The wrapper type for this type is variable, by default it'll use [`Box`],
|
||||
/// but you can change that by setting "`--cfg=ruma_identifiers_storage=...`" using
|
||||
/// `RUSTFLAGS` or `.cargo/config.toml` (under `[build]` -> `rustflags = ["..."]`)
|
||||
/// to the following;
|
||||
/// - `ruma_identifiers_storage="Arc"` to use [`Arc`](std::sync::Arc) as a wrapper type.
|
||||
pub struct #owned #impl_generics {
|
||||
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
|
||||
inner: Box<#id_ty>,
|
||||
#[cfg(ruma_identifiers_storage = "Arc")]
|
||||
inner: std::sync::Arc<#id_ty>,
|
||||
inner: #sv_decl,
|
||||
#phantom_decl
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics #owned_ty {
|
||||
fn from_ref(v: &#id_ty) -> Self {
|
||||
fn new(inner: #sv_decl) -> Self {
|
||||
Self {
|
||||
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
|
||||
inner: #id::from_box(v.as_str().into()),
|
||||
#[cfg(ruma_identifiers_storage = "Arc")]
|
||||
inner: #id::from_arc(v.as_str().into()),
|
||||
inner,
|
||||
#phantom_impl
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -281,38 +301,37 @@ fn expand_owned_id(input: &ItemStruct) -> TokenStream {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics AsRef<#id_ty> for #owned_ty {
|
||||
fn as_ref(&self) -> &#id_ty {
|
||||
&*self.inner
|
||||
let s: &str = self.as_ref();
|
||||
<#id_ty>::from_borrowed(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics AsRef<str> for #owned_ty {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.inner.as_str()
|
||||
let s: &[u8] = self.as_ref();
|
||||
unsafe { std::str::from_utf8_unchecked(s) }
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics AsRef<[u8]> for #owned_ty {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.inner.as_bytes()
|
||||
self.inner.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics From<#owned_ty> for String {
|
||||
fn from(id: #owned_ty) -> String {
|
||||
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
|
||||
{ id.inner.into() }
|
||||
#[cfg(ruma_identifiers_storage = "Arc")]
|
||||
{ id.inner.as_ref().into() }
|
||||
unsafe { String::from_utf8_unchecked(id.inner.into_vec()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics std::clone::Clone for #owned_ty {
|
||||
fn clone(&self) -> Self {
|
||||
(&*self.inner).into()
|
||||
Self::new(self.inner.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,7 +340,7 @@ fn expand_owned_id(input: &ItemStruct) -> TokenStream {
|
||||
type Target = #id_ty;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,46 +354,35 @@ fn expand_owned_id(input: &ItemStruct) -> TokenStream {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics From<&'_ #id_ty> for #owned_ty {
|
||||
fn from(id: &#id_ty) -> #owned_ty {
|
||||
#owned { inner: id.into() }
|
||||
Self::new(id.as_bytes().into())
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics From<Box<#id_ty>> for #owned_ty {
|
||||
fn from(b: Box<#id_ty>) -> #owned_ty {
|
||||
Self { inner: b.into() }
|
||||
Self::new(<#id_ty>::into_owned(b))
|
||||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
|
||||
inner: a.as_ref().into(),
|
||||
#[cfg(ruma_identifiers_storage = "Arc")]
|
||||
inner: a,
|
||||
}
|
||||
Self::new(a.as_bytes().into()) //TODO
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics From<#owned_ty> for Box<#id_ty> {
|
||||
fn from(a: #owned_ty) -> Box<#id_ty> {
|
||||
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
|
||||
{ a.inner }
|
||||
#[cfg(ruma_identifiers_storage = "Arc")]
|
||||
{ a.inner.as_ref().into() }
|
||||
{ Box::from(<#id_ty>::from_borrowed(a.as_str())) }
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics From<#owned_ty> for std::sync::Arc<#id_ty> {
|
||||
fn from(a: #owned_ty) -> std::sync::Arc<#id_ty> {
|
||||
#[cfg(not(any(ruma_identifiers_storage = "Arc")))]
|
||||
{ a.inner.into() }
|
||||
#[cfg(ruma_identifiers_storage = "Arc")]
|
||||
{ a.inner }
|
||||
{ std::sync::Arc::from(<#id_ty>::from_borrowed(a.as_str())) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,20 +481,19 @@ fn expand_owned_id(input: &ItemStruct) -> 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 id = &input.ident;
|
||||
let owned = format_ident!("Owned{id}");
|
||||
let id_ty = quote! { #id #ty_generics };
|
||||
let owned_ty = quote! { #owned #ty_generics };
|
||||
|
||||
let parse_doc_header = format!("Try parsing a `&str` into an `Owned{id}`.");
|
||||
let parse_box_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}>`.");
|
||||
|
||||
let id_ty = quote! { #id #ty_generics };
|
||||
let owned_ty = quote! { #owned #ty_generics };
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics #id_ty {
|
||||
@ -498,9 +505,8 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
pub fn parse(
|
||||
s: impl AsRef<str>,
|
||||
) -> Result<#owned_ty, crate::IdParseError> {
|
||||
let s = s.as_ref();
|
||||
#validate(s)?;
|
||||
Ok(#id::from_borrowed(s).to_owned())
|
||||
#validate(s.as_ref())?;
|
||||
Ok((<#id_ty>::from_borrowed(s.as_ref())).to_owned())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -512,7 +518,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
s: impl AsRef<str> + Into<Box<str>>,
|
||||
) -> Result<Box<Self>, crate::IdParseError> {
|
||||
#validate(s.as_ref())?;
|
||||
Ok(#id::from_box(s.into()))
|
||||
Ok(<#id_ty>::from_box(s.into()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -521,7 +527,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
s: impl AsRef<str> + Into<std::rc::Rc<str>>,
|
||||
) -> Result<std::rc::Rc<Self>, crate::IdParseError> {
|
||||
#validate(s.as_ref())?;
|
||||
Ok(#id::from_rc(s.into()))
|
||||
Ok(<#id_ty>::from_rc(s.into()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -530,7 +536,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
s: impl AsRef<str> + Into<std::sync::Arc<str>>,
|
||||
) -> Result<std::sync::Arc<Self>, crate::IdParseError> {
|
||||
#validate(s.as_ref())?;
|
||||
Ok(#id::from_arc(s.into()))
|
||||
Ok(<#id_ty>::from_arc(s.into()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,7 +550,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
|
||||
let s = String::deserialize(deserializer)?;
|
||||
|
||||
match #id::parse_box(s) {
|
||||
match <#id_ty>::parse_box(s) {
|
||||
Ok(o) => Ok(o),
|
||||
Err(e) => Err(D::Error::custom(e)),
|
||||
}
|
||||
@ -561,7 +567,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
|
||||
let s = String::deserialize(deserializer)?;
|
||||
|
||||
match #id::parse(s) {
|
||||
match <#id_ty>::parse(s) {
|
||||
Ok(o) => Ok(o),
|
||||
Err(e) => Err(D::Error::custom(e)),
|
||||
}
|
||||
@ -656,7 +662,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
type Error = crate::IdParseError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
<#id_ty>::parse_box(s)
|
||||
<#id_ty>::parse_box(s.into_boxed_str())
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,97 +696,103 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream {
|
||||
}
|
||||
|
||||
fn expand_unchecked_impls(input: &ItemStruct) -> TokenStream {
|
||||
let (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl();
|
||||
let generic_params = &input.generics.params;
|
||||
|
||||
let id = &input.ident;
|
||||
let owned = format_ident!("Owned{id}");
|
||||
let id_ty = quote! { #id #ty_generics };
|
||||
let owned_ty = quote! { #owned #ty_generics };
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl<'a> From<&'a str> for &'a #id {
|
||||
impl<'a, #generic_params> From<&'a str> for &'a #id_ty {
|
||||
fn from(s: &'a str) -> Self {
|
||||
#id::from_borrowed(s)
|
||||
<#id_ty>::from_borrowed(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl From<&str> for #owned {
|
||||
impl #impl_generics From<&str> for #owned_ty {
|
||||
fn from(s: &str) -> Self {
|
||||
<&#id>::from(s).into()
|
||||
<&#id_ty>::from(s).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl From<Box<str>> for #owned {
|
||||
impl #impl_generics From<Box<str>> for #owned_ty {
|
||||
fn from(s: Box<str>) -> Self {
|
||||
<&#id>::from(&*s).into()
|
||||
let s: String = s.into();
|
||||
Self::from(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl From<String> for #owned {
|
||||
impl #impl_generics From<String> for #owned_ty {
|
||||
fn from(s: String) -> Self {
|
||||
<&#id>::from(s.as_str()).into()
|
||||
Self::new(s.into_bytes().into())
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl From<&str> for Box<#id> {
|
||||
impl #impl_generics From<&str> for Box<#id_ty> {
|
||||
fn from(s: &str) -> Self {
|
||||
#id::from_box(s.into())
|
||||
Self::from(s.to_owned().into_boxed_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl From<Box<str>> for Box<#id> {
|
||||
impl #impl_generics From<Box<str>> for Box<#id_ty> {
|
||||
fn from(s: Box<str>) -> Self {
|
||||
#id::from_box(s)
|
||||
<#id_ty>::from_box(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl From<String> for Box<#id> {
|
||||
impl #impl_generics From<String> for Box<#id_ty> {
|
||||
fn from(s: String) -> Self {
|
||||
#id::from_box(s.into())
|
||||
let s = s.into_boxed_str();
|
||||
Self::from(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl From<Box<#id>> for Box<str> {
|
||||
fn from(id: Box<#id>) -> Self {
|
||||
id.into_owned()
|
||||
impl #impl_generics From<Box<#id_ty>> for Box<str> {
|
||||
fn from(id: Box<#id_ty>) -> Self {
|
||||
<#id_ty>::into_box(id)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl<'de> serde::Deserialize<'de> for Box<#id> {
|
||||
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>,
|
||||
{
|
||||
Box::<str>::deserialize(deserializer).map(#id::from_box)
|
||||
Box::<str>::deserialize(deserializer).map(<#id_ty>::from_box)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl<'de> serde::Deserialize<'de> for #owned {
|
||||
impl<'de, #generic_params> serde::Deserialize<'de> for #owned_ty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
// FIXME: Deserialize inner, convert that
|
||||
Box::<str>::deserialize(deserializer).map(#id::from_box).map(Into::into)
|
||||
Box::<str>::deserialize(deserializer).map(<#id_ty>::from_box).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl<'de> serde::Deserialize<'de> for &'de #id {
|
||||
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>,
|
||||
{
|
||||
<&'de str>::deserialize(deserializer).map(<#id>::from_borrowed).map(Into::into)
|
||||
<&'de str>::deserialize(deserializer).map(<#id_ty>::from_borrowed).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -830,8 +842,7 @@ fn expand_partial_eq_string(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -
|
||||
#[automatically_derived]
|
||||
impl #impl_generics PartialEq<#rhs> for #lhs {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -841,11 +852,13 @@ fn expand_partial_eq_string(ty: TokenStream, impl_generics: &ImplGenerics<'_>) -
|
||||
|
||||
mod kw {
|
||||
syn::custom_keyword!(validate);
|
||||
syn::custom_keyword!(inline_bytes);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct IdZstMeta {
|
||||
validate: Option<Path>,
|
||||
inline_bytes: Option<usize>,
|
||||
}
|
||||
|
||||
impl IdZstMeta {
|
||||
@ -860,7 +873,17 @@ impl IdZstMeta {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self { validate })
|
||||
let inline_bytes = match (self.inline_bytes, other.inline_bytes) {
|
||||
(None, None) => None,
|
||||
(Some(val), None) | (None, Some(val)) => Some(val),
|
||||
(Some(a), Some(b)) => {
|
||||
let mut error = syn::Error::new_spanned(b, "duplicate attribute argument");
|
||||
error.combine(syn::Error::new_spanned(a, "note: first one here"));
|
||||
return Err(error);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self { validate, inline_bytes })
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,6 +892,15 @@ impl Parse for IdZstMeta {
|
||||
let _: kw::validate = input.parse()?;
|
||||
let _: Token![=] = input.parse()?;
|
||||
let validate = Some(input.parse()?);
|
||||
Ok(Self { validate })
|
||||
|
||||
let _: Option<Token![,]> = input.parse()?;
|
||||
|
||||
let _: Option<kw::inline_bytes> = input.parse()?;
|
||||
let _: Option<Token![=]> = input.parse()?;
|
||||
let inline_bytes: Option<syn::LitInt> = input.parse()?;
|
||||
let inline_bytes =
|
||||
inline_bytes.map(|ib| ib.base10_digits().parse().expect("inline_bytes is an integer"));
|
||||
|
||||
Ok(Self { validate, inline_bytes })
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user