From c1e8f1122ece8e6a6575d9a66d5a33ed33f17ff9 Mon Sep 17 00:00:00 2001 From: jinrui Date: Tue, 26 Nov 2024 17:28:55 +0800 Subject: [PATCH] feat(rspack_cacheable): `as` attr support use with dyn trait (#8535) * feat(rspack_cacheable): `as` attr support use with dyn trait * fix: ci --- crates/rspack_cacheable/src/context.rs | 8 +- crates/rspack_cacheable/src/with/as.rs | 4 +- .../rspack_cacheable/src/with/as_cacheable.rs | 4 +- crates/rspack_cacheable/src/with/as_inner.rs | 2 +- crates/rspack_cacheable/src/with/as_map.rs | 5 +- .../rspack_cacheable/src/with/as_ref_str.rs | 4 +- crates/rspack_cacheable/src/with/as_string.rs | 4 +- crates/rspack_cacheable/src/with/as_tuple2.rs | 5 +- crates/rspack_cacheable/src/with/as_tuple3.rs | 5 +- crates/rspack_cacheable/src/with/as_vec.rs | 2 +- crates/rspack_cacheable/src/with/inline.rs | 2 +- .../rspack_cacheable/src/with/unsupported.rs | 4 +- .../tests/macro/cacheable/as_attr.rs | 70 ++++++++++++----- .../tests/macro/manual_cacheable/as_attr.rs | 77 ++++++++++++++----- crates/rspack_macros/src/cacheable/impl_as.rs | 32 +++++++- 15 files changed, 160 insertions(+), 68 deletions(-) diff --git a/crates/rspack_cacheable/src/context.rs b/crates/rspack_cacheable/src/context.rs index 6a37e24e36b..9a33663a20a 100644 --- a/crates/rspack_cacheable/src/context.rs +++ b/crates/rspack_cacheable/src/context.rs @@ -20,7 +20,7 @@ impl<'a> ContextGuard<'a> { Self { context } } - pub fn add_to_sharing>( + pub fn add_to_sharing + ?Sized>( &self, sharing: &mut S, ) -> Result<(), SerializeError> { @@ -28,7 +28,7 @@ impl<'a> ContextGuard<'a> { sharing.finish_sharing(CONTEXT_ADDR, self as *const _ as usize) } - pub fn sharing_context>( + pub fn sharing_context + ?Sized>( sharing: &'a mut S, ) -> Result<&'a dyn Any, SerializeError> { match sharing.start_sharing(CONTEXT_ADDR) { @@ -40,7 +40,7 @@ impl<'a> ContextGuard<'a> { } } - pub fn add_to_pooling>( + pub fn add_to_pooling + ?Sized>( &self, pooling: &mut P, ) -> Result<(), DeserializeError> { @@ -51,7 +51,7 @@ impl<'a> ContextGuard<'a> { } } - pub fn pooling_context>( + pub fn pooling_context + ?Sized>( pooling: &'a mut P, ) -> Result<&'a dyn Any, DeserializeError> { match pooling.start_pooling(CONTEXT_ADDR) { diff --git a/crates/rspack_cacheable/src/with/as.rs b/crates/rspack_cacheable/src/with/as.rs index 6167960f68c..6610a11ac74 100644 --- a/crates/rspack_cacheable/src/with/as.rs +++ b/crates/rspack_cacheable/src/with/as.rs @@ -43,7 +43,7 @@ where impl SerializeWith for As where A: AsConverter + Archive + Serialize, - S: Fallible + Sharing, + S: Fallible + Sharing + ?Sized, { #[inline] fn serialize_with(field: &T, serializer: &mut S) -> Result { @@ -60,7 +60,7 @@ impl DeserializeWith, T, D> for As where A: AsConverter + Archive, A::Archived: Deserialize, - D: Fallible + Pooling, + D: Fallible + Pooling + ?Sized, { #[inline] fn deserialize_with(field: &Archived, de: &mut D) -> Result { diff --git a/crates/rspack_cacheable/src/with/as_cacheable.rs b/crates/rspack_cacheable/src/with/as_cacheable.rs index 8e5585c612b..2532ce6e18a 100644 --- a/crates/rspack_cacheable/src/with/as_cacheable.rs +++ b/crates/rspack_cacheable/src/with/as_cacheable.rs @@ -20,7 +20,7 @@ impl ArchiveWith for AsCacheable { impl SerializeWith for AsCacheable where T: Archive + Serialize, - S: ?Sized + Fallible, + S: Fallible + ?Sized, { #[inline] fn serialize_with(field: &T, serializer: &mut S) -> Result { @@ -32,7 +32,7 @@ impl DeserializeWith, T, D> for AsCacheable where T: Archive, T::Archived: Deserialize, - D: ?Sized + Fallible, + D: Fallible + ?Sized, { #[inline] fn deserialize_with(field: &Archived, de: &mut D) -> Result { diff --git a/crates/rspack_cacheable/src/with/as_inner.rs b/crates/rspack_cacheable/src/with/as_inner.rs index 5d30ff32614..8b78295e288 100644 --- a/crates/rspack_cacheable/src/with/as_inner.rs +++ b/crates/rspack_cacheable/src/with/as_inner.rs @@ -48,7 +48,7 @@ impl DeserializeWith for AsInner where T: AsInnerConverter, A: ArchiveWith + DeserializeWith, - D: ?Sized + Fallible, + D: Fallible + ?Sized, { fn deserialize_with(field: &A::Archived, d: &mut D) -> Result { Ok(T::from_inner(A::deserialize_with(field, d)?)) diff --git a/crates/rspack_cacheable/src/with/as_map.rs b/crates/rspack_cacheable/src/with/as_map.rs index 904e494a881..53815474153 100644 --- a/crates/rspack_cacheable/src/with/as_map.rs +++ b/crates/rspack_cacheable/src/with/as_map.rs @@ -57,10 +57,11 @@ where } } -impl Serialize for Entry<&'_ K, &'_ V, WK, WV> +impl Serialize for Entry<&'_ K, &'_ V, WK, WV> where WK: SerializeWith, WV: SerializeWith, + S: Fallible + ?Sized, { #[inline] fn serialize(&self, serializer: &mut S) -> Result { @@ -90,7 +91,7 @@ where T: AsMapConverter, WK: ArchiveWith, WV: ArchiveWith, - S: Fallible + ?Sized + Allocator + Writer, + S: Fallible + Allocator + Writer + ?Sized, for<'a> Entry<&'a K, &'a V, WK, WV>: Serialize, { fn serialize_with(field: &T, s: &mut S) -> Result { diff --git a/crates/rspack_cacheable/src/with/as_ref_str.rs b/crates/rspack_cacheable/src/with/as_ref_str.rs index 8d528d1f554..ec1d1abaf78 100644 --- a/crates/rspack_cacheable/src/with/as_ref_str.rs +++ b/crates/rspack_cacheable/src/with/as_ref_str.rs @@ -31,7 +31,7 @@ where impl SerializeWith for AsRefStr where T: AsRefStrConverter, - S: ?Sized + Fallible + Writer, + S: Fallible + Writer + ?Sized, S::Error: Source, { #[inline] @@ -43,7 +43,7 @@ where impl DeserializeWith for AsRefStr where T: AsRefStrConverter, - D: ?Sized + Fallible, + D: Fallible + ?Sized, { #[inline] fn deserialize_with(field: &ArchivedString, _: &mut D) -> Result { diff --git a/crates/rspack_cacheable/src/with/as_string.rs b/crates/rspack_cacheable/src/with/as_string.rs index 82edfa18567..a7003758966 100644 --- a/crates/rspack_cacheable/src/with/as_string.rs +++ b/crates/rspack_cacheable/src/with/as_string.rs @@ -39,7 +39,7 @@ where impl SerializeWith for AsString where T: AsStringConverter, - S: Fallible + Writer, + S: Fallible + Writer + ?Sized, { #[inline] fn serialize_with(field: &T, serializer: &mut S) -> Result { @@ -52,7 +52,7 @@ where impl DeserializeWith for AsString where T: AsStringConverter, - D: Fallible, + D: Fallible + ?Sized, { #[inline] fn deserialize_with(field: &ArchivedString, _: &mut D) -> Result { diff --git a/crates/rspack_cacheable/src/with/as_tuple2.rs b/crates/rspack_cacheable/src/with/as_tuple2.rs index 28c6c2105ee..52e23de9b1c 100644 --- a/crates/rspack_cacheable/src/with/as_tuple2.rs +++ b/crates/rspack_cacheable/src/with/as_tuple2.rs @@ -30,10 +30,11 @@ where } } -impl SerializeWith<(K, V), S> for AsTuple2 +impl SerializeWith<(K, V), S> for AsTuple2 where A: SerializeWith, B: SerializeWith, + S: Fallible + ?Sized, { #[inline] fn serialize_with(field: &(K, V), serializer: &mut S) -> Result { @@ -49,7 +50,7 @@ impl DeserializeWith, (K where A: ArchiveWith + DeserializeWith, B: ArchiveWith + DeserializeWith, - D: ?Sized + Fallible, + D: Fallible + ?Sized, { fn deserialize_with( field: &ArchivedTuple2, diff --git a/crates/rspack_cacheable/src/with/as_tuple3.rs b/crates/rspack_cacheable/src/with/as_tuple3.rs index 7ade245128a..464ea248dcd 100644 --- a/crates/rspack_cacheable/src/with/as_tuple3.rs +++ b/crates/rspack_cacheable/src/with/as_tuple3.rs @@ -34,11 +34,12 @@ where } } -impl SerializeWith<(K, V, H), S> for AsTuple3 +impl SerializeWith<(K, V, H), S> for AsTuple3 where A: SerializeWith, B: SerializeWith, C: SerializeWith, + S: Fallible + ?Sized, { #[inline] fn serialize_with(field: &(K, V, H), serializer: &mut S) -> Result { @@ -57,7 +58,7 @@ where A: ArchiveWith + DeserializeWith, B: ArchiveWith + DeserializeWith, C: ArchiveWith + DeserializeWith, - D: ?Sized + Fallible, + D: Fallible + ?Sized, { fn deserialize_with( field: &ArchivedTuple3, diff --git a/crates/rspack_cacheable/src/with/as_vec.rs b/crates/rspack_cacheable/src/with/as_vec.rs index fe92f29ca1e..626055f5f3a 100644 --- a/crates/rspack_cacheable/src/with/as_vec.rs +++ b/crates/rspack_cacheable/src/with/as_vec.rs @@ -79,7 +79,7 @@ where impl DeserializeWith, T, D> for AsVec where T: AsVecConverter, - D: Fallible, + D: Fallible + ?Sized, A: ArchiveWith + DeserializeWith, { fn deserialize_with(field: &ArchivedVec, d: &mut D) -> Result { diff --git a/crates/rspack_cacheable/src/with/inline.rs b/crates/rspack_cacheable/src/with/inline.rs index 4288b5e4b26..07a87fea12e 100644 --- a/crates/rspack_cacheable/src/with/inline.rs +++ b/crates/rspack_cacheable/src/with/inline.rs @@ -26,7 +26,7 @@ where impl<'a, T, F, S> SerializeWith<&'a F, S> for Inline where T: SerializeWith, - S: ?Sized + Fallible, + S: Fallible + ?Sized, { #[inline] fn serialize_with(field: &&F, serializer: &mut S) -> Result { diff --git a/crates/rspack_cacheable/src/with/unsupported.rs b/crates/rspack_cacheable/src/with/unsupported.rs index 66841ffabcb..7846a96516e 100644 --- a/crates/rspack_cacheable/src/with/unsupported.rs +++ b/crates/rspack_cacheable/src/with/unsupported.rs @@ -17,7 +17,7 @@ impl ArchiveWith for Unsupported { impl SerializeWith for Unsupported where - S: Fallible, + S: Fallible + ?Sized, { fn serialize_with(_: &F, _: &mut S) -> Result<(), SerializeError> { Err(SerializeError::UnsupportedField) @@ -26,7 +26,7 @@ where impl DeserializeWith<(), F, D> for Unsupported where - D: Fallible, + D: Fallible + ?Sized, { fn deserialize_with(_: &(), _: &mut D) -> Result { Err(DeserializeError::UnsupportedField) diff --git a/crates/rspack_cacheable_test/tests/macro/cacheable/as_attr.rs b/crates/rspack_cacheable_test/tests/macro/cacheable/as_attr.rs index 5636f1249db..d1e95076443 100644 --- a/crates/rspack_cacheable_test/tests/macro/cacheable/as_attr.rs +++ b/crates/rspack_cacheable_test/tests/macro/cacheable/as_attr.rs @@ -1,34 +1,62 @@ use rspack_cacheable::{ - cacheable, from_bytes, to_bytes, - with::{AsTuple2, Inline}, + cacheable, cacheable_dyn, from_bytes, to_bytes, + with::{AsOption, AsTuple2, AsVec, Inline}, }; +#[cacheable_dyn] +trait Module {} + +#[cacheable] +struct NormalModule { + inner: String, +} + +#[cacheable_dyn] +impl Module for NormalModule {} + #[cacheable] -#[derive(Debug, PartialEq, Eq)] -struct Person { - name: String, - content: (String, String), +struct Data { + block1: String, + block2: Vec<(String, Option)>, + block3: Box, } -#[cacheable(as=Person)] -struct PersonRef<'a> { - #[rkyv(with=Inline)] - name: &'a String, - #[rkyv(with=AsTuple2)] - content: (&'a String, &'a String), +#[cacheable(as=Data)] +struct DataRef<'a> { + #[cacheable(with=Inline)] + block1: &'a String, + #[cacheable(with=AsVec>>)] + block2: Vec<(&'a String, Option<&'a String>)>, + #[allow(clippy::borrowed_box)] + #[cacheable(with=Inline)] + block3: &'a Box, } #[test] +#[cfg_attr(miri, ignore)] fn as_attr() { - let a = Person { - name: "abc".into(), - content: ("a".into(), "b".into()), + let a = Data { + block1: "abc".into(), + block2: vec![ + ("key1".into(), None), + ("key2".into(), Some("value2".into())), + ("key3".into(), Some("value3".into())), + ], + block3: Box::new(NormalModule { + inner: "inner".into(), + }), }; - let a_ref = PersonRef { - name: &a.name, - content: (&a.content.0, &a.content.1), + let a_ref = DataRef { + block1: &a.block1, + block2: a + .block2 + .iter() + .map(|(key, value)| (key, value.as_ref())) + .collect(), + block3: &a.block3, }; - let bytes = to_bytes(&a_ref, &()).unwrap(); - let deserialize_a: Person = from_bytes(&bytes, &()).unwrap(); - assert_eq!(a, deserialize_a); + let bytes = to_bytes(&a, &()).unwrap(); + let bytes_ref = to_bytes(&a_ref, &()).unwrap(); + assert_eq!(bytes, bytes_ref); + from_bytes::(&bytes, &()).unwrap(); } diff --git a/crates/rspack_cacheable_test/tests/macro/manual_cacheable/as_attr.rs b/crates/rspack_cacheable_test/tests/macro/manual_cacheable/as_attr.rs index a284a81b688..8fdccb1dca4 100644 --- a/crates/rspack_cacheable_test/tests/macro/manual_cacheable/as_attr.rs +++ b/crates/rspack_cacheable_test/tests/macro/manual_cacheable/as_attr.rs @@ -1,48 +1,85 @@ use rspack_cacheable::{ - from_bytes, to_bytes, - with::{AsTuple2, Inline}, + cacheable_dyn, from_bytes, to_bytes, + with::{AsOption, AsTuple2, AsVec, Inline}, }; +#[cacheable_dyn] +trait Module {} + +#[derive( + rspack_cacheable::__private::rkyv::Archive, + rspack_cacheable::__private::rkyv::Deserialize, + rspack_cacheable::__private::rkyv::Serialize, +)] +#[rkyv(crate=rspack_cacheable::__private::rkyv)] +struct NormalModule { + inner: String, +} + +#[cacheable_dyn] +impl Module for NormalModule {} + #[derive( rspack_cacheable::__private::rkyv::Archive, rspack_cacheable::__private::rkyv::Deserialize, rspack_cacheable::__private::rkyv::Serialize, )] #[rkyv(crate=rspack_cacheable::__private::rkyv)] -#[derive(Debug, PartialEq, Eq)] -struct Person { - name: String, - content: (String, String), +struct Data { + block1: String, + block2: Vec<(String, Option)>, + block3: Box, } #[derive( rspack_cacheable::__private::rkyv::Archive, rspack_cacheable::__private::rkyv::Serialize, )] #[rkyv(crate=rspack_cacheable::__private::rkyv, - as=rspack_cacheable::__private::rkyv::Archived)] + as=rspack_cacheable::__private::rkyv::Archived)] #[rkyv(serialize_bounds( __S: rspack_cacheable::__private::rkyv::ser::Writer + rspack_cacheable::__private::rkyv::ser::Allocator + rspack_cacheable::__private::rkyv::rancor::Fallible, + Inline: rspack_cacheable::__private::rkyv::with::SerializeWith<&'a String, __S>, + AsVec>>: rspack_cacheable::__private::rkyv::with::SerializeWith)>, __S>, + Inline: rspack_cacheable::__private::rkyv::with::SerializeWith<&'a Box, __S> ))] -struct PersonRef<'a> { +struct DataRef<'a> { #[rkyv(omit_bounds)] #[rkyv(with=Inline)] - name: &'a String, + block1: &'a String, + #[rkyv(omit_bounds)] + #[rkyv(with=AsVec>>)] + block2: Vec<(&'a String, Option<&'a String>)>, + #[allow(clippy::borrowed_box)] #[rkyv(omit_bounds)] - #[rkyv(with=AsTuple2)] - content: (&'a String, &'a String), + #[rkyv(with=Inline)] + block3: &'a Box, } #[test] +#[cfg_attr(miri, ignore)] fn as_attr() { - let a = Person { - name: "abc".into(), - content: ("a".into(), "b".into()), + let a = Data { + block1: "abc".into(), + block2: vec![ + ("key1".into(), None), + ("key2".into(), Some("value2".into())), + ("key3".into(), Some("value3".into())), + ], + block3: Box::new(NormalModule { + inner: "inner".into(), + }), }; - let a_ref = PersonRef { - name: &a.name, - content: (&a.content.0, &a.content.1), + let a_ref = DataRef { + block1: &a.block1, + block2: a + .block2 + .iter() + .map(|(key, value)| (key, value.as_ref())) + .collect(), + block3: &a.block3, }; - let bytes = to_bytes(&a_ref, &()).unwrap(); - let deserialize_a: Person = from_bytes(&bytes, &()).unwrap(); - assert_eq!(a, deserialize_a); + let bytes = to_bytes(&a, &()).unwrap(); + let bytes_ref = to_bytes(&a_ref, &()).unwrap(); + assert_eq!(bytes, bytes_ref); + from_bytes::(&bytes, &()).unwrap(); } diff --git a/crates/rspack_macros/src/cacheable/impl_as.rs b/crates/rspack_macros/src/cacheable/impl_as.rs index 1bdc1211005..37051eaa6cd 100644 --- a/crates/rspack_macros/src/cacheable/impl_as.rs +++ b/crates/rspack_macros/src/cacheable/impl_as.rs @@ -4,10 +4,26 @@ use syn::{parse_macro_input, parse_quote, visit_mut::VisitMut, Field, Item, Toke use super::CacheableArgs; -/// A visitor to add #[cacheable(omit_bounds)] on field -struct AddFieldAttrVisitor; +/// A visitor to add #[cacheable(omit_bounds)] and collect #[cacheable(with=...)] info on field +#[derive(Default)] +struct FieldAttrVisitor { + /// with info collected + /// + /// # Example + /// + /// ```rust,ignore + /// #[cacheable] + /// struct Test { + /// #[cacheable(with=AsMap)] + /// test_field: HashMap, + /// } + /// + /// // with_info is vec![(AsMap, HashMap)] + /// ``` + with_info: Vec<(Type, Type)>, +} -impl VisitMut for AddFieldAttrVisitor { +impl VisitMut for FieldAttrVisitor { fn visit_field_mut(&mut self, f: &mut Field) { let mut with_info = None; f.attrs.retain(|item| { @@ -32,6 +48,7 @@ impl VisitMut for AddFieldAttrVisitor { // add rkyv with if let Some(with_info) = with_info { f.attrs.push(parse_quote!(#[rkyv(with=#with_info)])); + self.with_info.push((with_info, f.ty.clone())); } // add rkyv omit_bounds f.attrs.push(parse_quote!(#[rkyv(omit_bounds)])); @@ -42,12 +59,18 @@ impl VisitMut for AddFieldAttrVisitor { pub fn impl_cacheable_as(tokens: TokenStream, args: CacheableArgs) -> TokenStream { let mut input = parse_macro_input!(tokens as Item); - let mut visitor = AddFieldAttrVisitor; + let mut visitor = FieldAttrVisitor::default(); visitor.visit_item_mut(&mut input); let crate_path = &args.crate_path; let r#as = &args.r#as; + let serialize_bounds = visitor + .with_info + .iter() + .map(|(with, ty)| quote!(#with: #crate_path::__private::rkyv::with::SerializeWith<#ty, __S>)); + let serialize_bounds = quote! { #(#serialize_bounds),* }; + quote! { #[derive( #crate_path::__private::rkyv::Archive, @@ -59,6 +82,7 @@ pub fn impl_cacheable_as(tokens: TokenStream, args: CacheableArgs) -> TokenStrea )] #[rkyv(serialize_bounds( __S: #crate_path::__private::rkyv::ser::Writer + #crate_path::__private::rkyv::ser::Allocator + #crate_path::__private::rkyv::rancor::Fallible, + #serialize_bounds ))] #input }