Skip to content

Commit 78c0e36

Browse files
authored
feat: rspack_cacheable add custom with wrapper (#11711)
* feat: rspack_cacheable add custom with wrapper * fix typo
1 parent db3cf1b commit 78c0e36

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use std::any::Any;
2+
3+
use rkyv::{
4+
Archive, Deserialize, Place, Serialize,
5+
de::Pooling,
6+
rancor::Fallible,
7+
ser::Sharing,
8+
with::{ArchiveWith, DeserializeWith, SerializeWith},
9+
};
10+
11+
use crate::{DeserializeError, SerializeError, cacheable, context::ContextGuard};
12+
13+
/// A trait for writing custom serialization and deserialization.
14+
///
15+
/// `#[cacheable(with=Custom)]` will use this trait.
16+
pub trait CustomConverter {
17+
type Target: Archive;
18+
fn serialize(&self, ctx: &dyn Any) -> Result<Self::Target, SerializeError>;
19+
fn deserialize(data: Self::Target, ctx: &dyn Any) -> Result<Self, DeserializeError>
20+
where
21+
Self: Sized;
22+
}
23+
24+
/// A wrapper that uses CustomConverter for serialization.
25+
pub struct Custom;
26+
27+
/// A simple structure to save the generated `CustomConverter::Target`,
28+
/// which can avoid some deserialization conflicts.
29+
#[cacheable(crate=crate)]
30+
pub struct DataBox<T: Archive>(T);
31+
32+
pub struct CustomResolver<A: Archive> {
33+
resolver: DataBoxResolver<A>,
34+
value: DataBox<A>,
35+
}
36+
37+
impl<T> ArchiveWith<T> for Custom
38+
where
39+
T: CustomConverter,
40+
T::Target: Archive,
41+
{
42+
type Archived = ArchivedDataBox<T::Target>;
43+
type Resolver = CustomResolver<T::Target>;
44+
45+
#[inline]
46+
fn resolve_with(_field: &T, resolver: Self::Resolver, out: Place<Self::Archived>) {
47+
let CustomResolver { resolver, value } = resolver;
48+
value.resolve(resolver, out)
49+
}
50+
}
51+
52+
impl<T, S> SerializeWith<T, S> for Custom
53+
where
54+
T: CustomConverter,
55+
T::Target: Archive + Serialize<S>,
56+
S: Fallible<Error = SerializeError> + Sharing + ?Sized,
57+
{
58+
#[inline]
59+
fn serialize_with(field: &T, serializer: &mut S) -> Result<Self::Resolver, SerializeError> {
60+
let ctx = ContextGuard::sharing_context(serializer)?;
61+
let value = DataBox(T::serialize(field, ctx)?);
62+
Ok(CustomResolver {
63+
resolver: value.serialize(serializer)?,
64+
value,
65+
})
66+
}
67+
}
68+
69+
impl<T, D> DeserializeWith<ArchivedDataBox<T::Target>, T, D> for Custom
70+
where
71+
T: CustomConverter,
72+
T::Target: Archive,
73+
ArchivedDataBox<T::Target>: Deserialize<DataBox<T::Target>, D>,
74+
D: Fallible<Error = DeserializeError> + Pooling + ?Sized,
75+
{
76+
#[inline]
77+
fn deserialize_with(
78+
field: &ArchivedDataBox<T::Target>,
79+
de: &mut D,
80+
) -> Result<T, DeserializeError> {
81+
let value = field.deserialize(de)?;
82+
let ctx = ContextGuard::pooling_context(de)?;
83+
T::deserialize(value.0, ctx)
84+
}
85+
}

crates/rspack_cacheable/src/with/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod as_string;
99
mod as_tuple2;
1010
mod as_tuple3;
1111
mod as_vec;
12+
mod custom;
1213
mod inline;
1314
mod unsupported;
1415

@@ -23,6 +24,7 @@ pub use as_string::{AsString, AsStringConverter};
2324
pub use as_tuple2::AsTuple2;
2425
pub use as_tuple3::AsTuple3;
2526
pub use as_vec::{AsVec, AsVecConverter};
27+
pub use custom::{Custom, CustomConverter};
2628
pub use inline::Inline;
2729
pub use rkyv::with::{Map as AsOption, Skip};
2830
pub use unsupported::Unsupported;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::{any::Any, path::PathBuf};
2+
3+
use rspack_cacheable::{
4+
DeserializeError, SerializeError, enable_cacheable as cacheable,
5+
with::{Custom, CustomConverter},
6+
};
7+
8+
#[cacheable(with=Custom)]
9+
#[derive(Debug, PartialEq, Eq)]
10+
struct Data(PathBuf);
11+
12+
impl CustomConverter for Data {
13+
type Target = String;
14+
fn serialize(&self, _ctx: &dyn Any) -> Result<Self::Target, SerializeError> {
15+
Ok(self.0.to_string_lossy().to_string())
16+
}
17+
fn deserialize(data: Self::Target, _ctx: &dyn Any) -> Result<Self, DeserializeError> {
18+
Ok(Data(PathBuf::from(&data)))
19+
}
20+
}
21+
22+
#[test]
23+
fn test_custom() {
24+
let data = Data(PathBuf::from("/home/user"));
25+
26+
let bytes = rspack_cacheable::to_bytes(&data, &()).unwrap();
27+
let new_data: Data = rspack_cacheable::from_bytes(&bytes, &()).unwrap();
28+
assert_eq!(data, new_data);
29+
}

crates/rspack_cacheable_test/tests/with/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ mod as_string;
99
mod as_tuple2;
1010
mod as_tuple3;
1111
mod as_vec;
12+
mod custom;
1213
mod inline;
1314
mod unsupported;

0 commit comments

Comments
 (0)