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 = { version = "1.0.164", features = ["derive"] } | ||||||
| serde_html_form = "0.2.0" | serde_html_form = "0.2.0" | ||||||
| serde_json = "1.0.87" | serde_json = "1.0.87" | ||||||
|  | smallvec = { version = "1.13.2", features = ["const_generics", "const_new", "serde", "union", "write"] } | ||||||
| thiserror = "2.0.0" | thiserror = "2.0.0" | ||||||
| tracing = { version = "0.1.37", default-features = false, features = ["std"] } | tracing = { version = "0.1.37", default-features = false, features = ["std"] } | ||||||
| url = { version = "2.5.0" } | url = { version = "2.5.0" } | ||||||
|  | |||||||
| @ -79,6 +79,7 @@ ruma-macros = { workspace = true } | |||||||
| serde = { workspace = true } | serde = { workspace = true } | ||||||
| serde_html_form = { workspace = true } | serde_html_form = { workspace = true } | ||||||
| serde_json = { workspace = true, features = ["raw_value"] } | serde_json = { workspace = true, features = ["raw_value"] } | ||||||
|  | smallvec = { workspace = true } | ||||||
| thiserror = { workspace = true } | thiserror = { workspace = true } | ||||||
| time = "0.3.34" | time = "0.3.34" | ||||||
| tracing = { workspace = true, features = ["attributes"] } | 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
 | /// [room versions]: https://spec.matrix.org/latest/rooms/#complete-list-of-room-versions
 | ||||||
| #[repr(transparent)] | #[repr(transparent)] | ||||||
| #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)] | #[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); | pub struct EventId(str); | ||||||
| 
 | 
 | ||||||
| impl EventId { | impl EventId { | ||||||
|  | |||||||
| @ -75,6 +75,7 @@ ruma-identifiers-validation = { workspace = true } | |||||||
| ruma-macros = { workspace = true } | ruma-macros = { workspace = true } | ||||||
| serde = { workspace = true } | serde = { workspace = true } | ||||||
| serde_json = { workspace = true, features = ["raw_value"] } | serde_json = { workspace = true, features = ["raw_value"] } | ||||||
|  | smallvec = { workspace = true } | ||||||
| thiserror = { workspace = true } | thiserror = { workspace = true } | ||||||
| tracing = { workspace = true, features = ["attributes"] } | tracing = { workspace = true, features = ["attributes"] } | ||||||
| url = { workspace = true } | url = { workspace = true } | ||||||
|  | |||||||
| @ -24,11 +24,6 @@ impl Parse for IdentifierInput { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> { | 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( |     let meta = input.attrs.iter().filter(|attr| attr.path().is_ident("ruma_id")).try_fold( | ||||||
|         IdZstMeta::default(), |         IdZstMeta::default(), | ||||||
|         |meta, attr| { |         |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
 |     // 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"); |     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 id = &input.ident; | ||||||
|     let as_bytes_docs = format!("Creates a byte slice from this `{id}`."); |     let owned = format_ident!("Owned{id}"); | ||||||
|     let max_bytes_docs = format!("Maximum byte length for any `{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 { |     let as_str_impl = match &input.fields { | ||||||
|         Fields::Named(_) | Fields::Unit => { |         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); |     let as_str_impls = expand_as_str_impls(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 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 | ||||||
| 
 | 
 | ||||||
| @ -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 _) } |                 unsafe { std::sync::Arc::from_raw(std::sync::Arc::into_raw(s) as _) } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             pub(super) fn into_owned(self: Box<Self>) -> Box<str> { |             pub(super) fn into_owned(self: Box<Self>) -> #sv_decl { | ||||||
|                 unsafe { Box::from_raw(Box::into_raw(self) as _) } |                 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] |             #[doc = #as_str_docs] | ||||||
| @ -129,7 +141,7 @@ pub fn expand_id_zst(input: ItemStruct) -> syn::Result<TokenStream> { | |||||||
|             type Owned = #owned_ty; |             type Owned = #owned_ty; | ||||||
| 
 | 
 | ||||||
|             fn to_owned(&self) -> Self::Owned { |             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] |         #[automatically_derived] | ||||||
|         impl #impl_generics From<Box<#id_ty>> for String { |         impl #impl_generics From<Box<#id_ty>> for String { | ||||||
|             fn from(id: Box<#id_ty>) -> Self { |             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 id = &input.ident; | ||||||
|     let owned = format_ident!("Owned{id}"); |     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 id_ty = quote! { #id #ty_generics }; | ||||||
|     let owned_ty = quote! { #owned #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 as_str_impls = expand_as_str_impls(owned_ty.clone(), &impl_generics); | ||||||
| 
 | 
 | ||||||
|  |     let doc_header = format!("Owned variant of {id}"); | ||||||
|  | 
 | ||||||
|     quote! { |     quote! { | ||||||
|         #[doc = #doc_header] |         #[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 { |         pub struct #owned #impl_generics { | ||||||
|             #[cfg(not(any(ruma_identifiers_storage = "Arc")))] |             inner: #sv_decl, | ||||||
|             inner: Box<#id_ty>, |             #phantom_decl | ||||||
|             #[cfg(ruma_identifiers_storage = "Arc")] |  | ||||||
|             inner: std::sync::Arc<#id_ty>, |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl #impl_generics #owned_ty { |         impl #impl_generics #owned_ty { | ||||||
|             fn from_ref(v: &#id_ty) -> Self { |             fn new(inner: #sv_decl) -> Self { | ||||||
|                 Self { |                 Self { | ||||||
|                     #[cfg(not(any(ruma_identifiers_storage = "Arc")))] |                     inner, | ||||||
|                     inner: #id::from_box(v.as_str().into()), |                     #phantom_impl | ||||||
|                     #[cfg(ruma_identifiers_storage = "Arc")] |  | ||||||
|                     inner: #id::from_arc(v.as_str().into()), |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -281,38 +301,37 @@ fn expand_owned_id(input: &ItemStruct) -> TokenStream { | |||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl #impl_generics AsRef<#id_ty> for #owned_ty { |         impl #impl_generics AsRef<#id_ty> for #owned_ty { | ||||||
|             fn as_ref(&self) -> &#id_ty { |             fn as_ref(&self) -> &#id_ty { | ||||||
|                 &*self.inner |                 let s: &str = self.as_ref(); | ||||||
|  |                 <#id_ty>::from_borrowed(s) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl #impl_generics AsRef<str> for #owned_ty { |         impl #impl_generics AsRef<str> for #owned_ty { | ||||||
|             fn as_ref(&self) -> &str { |             fn as_ref(&self) -> &str { | ||||||
|                 self.inner.as_str() |                 let s: &[u8] = self.as_ref(); | ||||||
|  |                 unsafe { std::str::from_utf8_unchecked(s) } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl #impl_generics AsRef<[u8]> for #owned_ty { |         impl #impl_generics AsRef<[u8]> for #owned_ty { | ||||||
|             fn as_ref(&self) -> &[u8] { |             fn as_ref(&self) -> &[u8] { | ||||||
|                 self.inner.as_bytes() |                 self.inner.as_slice() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl #impl_generics From<#owned_ty> for String { |         impl #impl_generics From<#owned_ty> for String { | ||||||
|             fn from(id: #owned_ty) -> String { |             fn from(id: #owned_ty) -> String { | ||||||
|                 #[cfg(not(any(ruma_identifiers_storage = "Arc")))] |                 unsafe { String::from_utf8_unchecked(id.inner.into_vec()) } | ||||||
|                 { id.inner.into() } |  | ||||||
|                 #[cfg(ruma_identifiers_storage = "Arc")] |  | ||||||
|                 { id.inner.as_ref().into() } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl #impl_generics std::clone::Clone for #owned_ty { |         impl #impl_generics std::clone::Clone for #owned_ty { | ||||||
|             fn clone(&self) -> Self { |             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; |             type Target = #id_ty; | ||||||
| 
 | 
 | ||||||
|             fn deref(&self) -> &Self::Target { |             fn deref(&self) -> &Self::Target { | ||||||
|                 &self.inner |                 self.as_ref() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -335,46 +354,35 @@ fn expand_owned_id(input: &ItemStruct) -> TokenStream { | |||||||
|         #[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 { | ||||||
|                 #owned { inner: id.into() } |                 Self::new(id.as_bytes().into()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl #impl_generics From<Box<#id_ty>> for #owned_ty { |         impl #impl_generics From<Box<#id_ty>> for #owned_ty { | ||||||
|             fn from(b: Box<#id_ty>) -> #owned_ty { |             fn from(b: Box<#id_ty>) -> #owned_ty { | ||||||
|                 Self { inner: b.into() } |                 Self::new(<#id_ty>::into_owned(b)) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[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(a: std::sync::Arc<#id_ty>) -> #owned_ty { | ||||||
|                 Self { |                 Self::new(a.as_bytes().into()) //TODO
 | ||||||
|                     #[cfg(not(any(ruma_identifiers_storage = "Arc")))] |  | ||||||
|                     inner: a.as_ref().into(), |  | ||||||
|                     #[cfg(ruma_identifiers_storage = "Arc")] |  | ||||||
|                     inner: a, |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[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(a: #owned_ty) -> Box<#id_ty> { | ||||||
|                 #[cfg(not(any(ruma_identifiers_storage = "Arc")))] |                 { Box::from(<#id_ty>::from_borrowed(a.as_str())) } | ||||||
|                 { a.inner } |  | ||||||
|                 #[cfg(ruma_identifiers_storage = "Arc")] |  | ||||||
|                 { a.inner.as_ref().into() } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[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(a: #owned_ty) -> std::sync::Arc<#id_ty> { | ||||||
|                 #[cfg(not(any(ruma_identifiers_storage = "Arc")))] |                 { std::sync::Arc::from(<#id_ty>::from_borrowed(a.as_str())) } | ||||||
|                 { a.inner.into() } |  | ||||||
|                 #[cfg(ruma_identifiers_storage = "Arc")] |  | ||||||
|                 { a.inner } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -473,20 +481,19 @@ fn expand_owned_id(input: &ItemStruct) -> TokenStream { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn expand_checked_impls(input: &ItemStruct, 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 (impl_generics, ty_generics, _where_clause) = input.generics.split_for_impl(); | ||||||
|     let generic_params = &input.generics.params; |     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_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_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_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 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! { |     quote! { | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl #impl_generics #id_ty { |         impl #impl_generics #id_ty { | ||||||
| @ -498,9 +505,8 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { | |||||||
|             pub fn parse( |             pub fn parse( | ||||||
|                 s: impl AsRef<str>, |                 s: impl AsRef<str>, | ||||||
|             ) -> Result<#owned_ty, crate::IdParseError> { |             ) -> Result<#owned_ty, crate::IdParseError> { | ||||||
|                 let s = s.as_ref(); |                 #validate(s.as_ref())?; | ||||||
|                 #validate(s)?; |                 Ok((<#id_ty>::from_borrowed(s.as_ref())).to_owned()) | ||||||
|                 Ok(#id::from_borrowed(s).to_owned()) |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[inline] |             #[inline] | ||||||
| @ -512,7 +518,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { | |||||||
|                 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())?; | ||||||
|                 Ok(#id::from_box(s.into())) |                 Ok(<#id_ty>::from_box(s.into())) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[inline] |             #[inline] | ||||||
| @ -521,7 +527,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { | |||||||
|                 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())?; | ||||||
|                 Ok(#id::from_rc(s.into())) |                 Ok(<#id_ty>::from_rc(s.into())) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[inline] |             #[inline] | ||||||
| @ -530,7 +536,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { | |||||||
|                 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())?; | ||||||
|                 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)?; |                 let s = String::deserialize(deserializer)?; | ||||||
| 
 | 
 | ||||||
|                 match #id::parse_box(s) { |                 match <#id_ty>::parse_box(s) { | ||||||
|                     Ok(o) => Ok(o), |                     Ok(o) => Ok(o), | ||||||
|                     Err(e) => Err(D::Error::custom(e)), |                     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)?; |                 let s = String::deserialize(deserializer)?; | ||||||
| 
 | 
 | ||||||
|                 match #id::parse(s) { |                 match <#id_ty>::parse(s) { | ||||||
|                     Ok(o) => Ok(o), |                     Ok(o) => Ok(o), | ||||||
|                     Err(e) => Err(D::Error::custom(e)), |                     Err(e) => Err(D::Error::custom(e)), | ||||||
|                 } |                 } | ||||||
| @ -656,7 +662,7 @@ fn expand_checked_impls(input: &ItemStruct, validate: Path) -> TokenStream { | |||||||
|             type Error = crate::IdParseError; |             type Error = crate::IdParseError; | ||||||
| 
 | 
 | ||||||
|             fn try_from(s: String) -> Result<Self, Self::Error> { |             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 { | 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 id = &input.ident; | ||||||
|     let owned = format_ident!("Owned{id}"); |     let owned = format_ident!("Owned{id}"); | ||||||
|  |     let id_ty = quote! { #id #ty_generics }; | ||||||
|  |     let owned_ty = quote! { #owned #ty_generics }; | ||||||
| 
 | 
 | ||||||
|     quote! { |     quote! { | ||||||
|         #[automatically_derived] |         #[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 { |             fn from(s: &'a str) -> Self { | ||||||
|                 #id::from_borrowed(s) |                 <#id_ty>::from_borrowed(s) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl From<&str> for #owned { |         impl #impl_generics From<&str> for #owned_ty { | ||||||
|             fn from(s: &str) -> Self { |             fn from(s: &str) -> Self { | ||||||
|                 <&#id>::from(s).into() |                 <&#id_ty>::from(s).into() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl From<Box<str>> for #owned { |         impl #impl_generics From<Box<str>> for #owned_ty { | ||||||
|             fn from(s: Box<str>) -> Self { |             fn from(s: Box<str>) -> Self { | ||||||
|                 <&#id>::from(&*s).into() |                 let s: String = s.into(); | ||||||
|  |                 Self::from(s) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl From<String> for #owned { |         impl #impl_generics From<String> for #owned_ty { | ||||||
|             fn from(s: String) -> Self { |             fn from(s: String) -> Self { | ||||||
|                 <&#id>::from(s.as_str()).into() |                 Self::new(s.into_bytes().into()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl From<&str> for Box<#id> { |         impl #impl_generics From<&str> for Box<#id_ty> { | ||||||
|             fn from(s: &str) -> Self { |             fn from(s: &str) -> Self { | ||||||
|                 #id::from_box(s.into()) |                 Self::from(s.to_owned().into_boxed_str()) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[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 { |             fn from(s: Box<str>) -> Self { | ||||||
|                 #id::from_box(s) |                 <#id_ty>::from_box(s) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl From<String> for Box<#id> { |         impl #impl_generics From<String> for Box<#id_ty> { | ||||||
|             fn from(s: String) -> Self { |             fn from(s: String) -> Self { | ||||||
|                 #id::from_box(s.into()) |                 let s = s.into_boxed_str(); | ||||||
|  |                 Self::from(s) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[automatically_derived] | ||||||
|         impl From<Box<#id>> for Box<str> { |         impl #impl_generics From<Box<#id_ty>> for Box<str> { | ||||||
|             fn from(id: Box<#id>) -> Self { |             fn from(id: Box<#id_ty>) -> Self { | ||||||
|                 id.into_owned() |                 <#id_ty>::into_box(id) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[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> |             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::from_box) |                 Box::<str>::deserialize(deserializer).map(<#id_ty>::from_box) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         #[automatically_derived] |         #[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> |             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||||||
|             where |             where | ||||||
|                 D: serde::Deserializer<'de>, |                 D: serde::Deserializer<'de>, | ||||||
|             { |             { | ||||||
|                 // FIXME: Deserialize inner, convert that
 |                 // 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] |         #[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> |             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>::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] |             #[automatically_derived] | ||||||
|             impl #impl_generics PartialEq<#rhs> for #lhs { |             impl #impl_generics PartialEq<#rhs> for #lhs { | ||||||
|                 fn eq(&self, other: &#rhs) -> bool { |                 fn eq(&self, other: &#rhs) -> bool { | ||||||
|                     AsRef::<str>::as_ref(self) |                     AsRef::<str>::as_ref(self) == AsRef::<str>::as_ref(other) | ||||||
|                         == AsRef::<str>::as_ref(other) |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -841,11 +852,13 @@ fn expand_partial_eq_string(ty: TokenStream, impl_generics: &ImplGenerics<'_>) - | |||||||
| 
 | 
 | ||||||
| mod kw { | mod kw { | ||||||
|     syn::custom_keyword!(validate); |     syn::custom_keyword!(validate); | ||||||
|  |     syn::custom_keyword!(inline_bytes); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Default)] | #[derive(Default)] | ||||||
| struct IdZstMeta { | struct IdZstMeta { | ||||||
|     validate: Option<Path>, |     validate: Option<Path>, | ||||||
|  |     inline_bytes: Option<usize>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl IdZstMeta { | 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 _: kw::validate = input.parse()?; | ||||||
|         let _: Token![=] = input.parse()?; |         let _: Token![=] = input.parse()?; | ||||||
|         let validate = Some(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