Skip to content

Commit 219a773

Browse files
authored
feat: rspack_cacheable context expose project root (#12685)
* feat: rspack_cacheable context expose project root * fix: comment
1 parent 29642b2 commit 219a773

File tree

14 files changed

+117
-62
lines changed

14 files changed

+117
-62
lines changed

crates/rspack_cacheable/src/context.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{any::Any, ptr::NonNull};
1+
use std::{any::Any, ops::Deref, path::Path, ptr::NonNull};
22

33
use rkyv::{
44
de::{ErasedPtr, Pooling, PoolingState},
@@ -10,13 +10,31 @@ use crate::error::{Error, Result};
1010
const CONTEXT_ADDR: usize = 0;
1111
unsafe fn default_drop(_: ErasedPtr) {}
1212

13+
pub trait CacheableContext: Any {
14+
fn project_root(&self) -> Option<&Path>;
15+
}
16+
17+
// Implement for unit type for convenience in tests and simple cases
18+
impl CacheableContext for () {
19+
fn project_root(&self) -> Option<&Path> {
20+
None
21+
}
22+
}
23+
1324
/// A context wrapper that provides shared context methods
1425
pub struct ContextGuard<'a> {
15-
context: &'a dyn Any,
26+
context: &'a dyn CacheableContext,
27+
}
28+
29+
impl<'a> Deref for ContextGuard<'a> {
30+
type Target = dyn CacheableContext;
31+
fn deref(&self) -> &Self::Target {
32+
self.context
33+
}
1634
}
1735

1836
impl<'a> ContextGuard<'a> {
19-
pub fn new(context: &'a dyn Any) -> Self {
37+
pub fn new(context: &'a dyn CacheableContext) -> Self {
2038
Self { context }
2139
}
2240

@@ -25,11 +43,11 @@ impl<'a> ContextGuard<'a> {
2543
sharing.finish_sharing(CONTEXT_ADDR, self as *const _ as usize)
2644
}
2745

28-
pub fn sharing_context<S: Sharing<Error> + ?Sized>(sharing: &'a mut S) -> Result<&'a dyn Any> {
46+
pub fn sharing_guard<S: Sharing<Error> + ?Sized>(sharing: &'a mut S) -> Result<&'a Self> {
2947
match sharing.start_sharing(CONTEXT_ADDR) {
3048
SharingState::Finished(addr) => {
3149
let guard: &Self = unsafe { &*(addr as *const Self) };
32-
Ok(guard.context)
50+
Ok(guard)
3351
}
3452
_ => Err(Error::NoContext),
3553
}
@@ -43,13 +61,19 @@ impl<'a> ContextGuard<'a> {
4361
}
4462
}
4563

46-
pub fn pooling_context<P: Pooling<Error> + ?Sized>(pooling: &'a mut P) -> Result<&'a dyn Any> {
64+
pub fn pooling_guard<P: Pooling<Error> + ?Sized>(pooling: &'a mut P) -> Result<&'a Self> {
4765
match pooling.start_pooling(CONTEXT_ADDR) {
4866
PoolingState::Finished(ptr) => {
4967
let guard: &Self = unsafe { &*(ptr.data_address() as *const Self) };
50-
Ok(guard.context)
68+
Ok(guard)
5169
}
5270
_ => Err(Error::NoContext),
5371
}
5472
}
73+
74+
pub fn downcast_context<T: 'static>(&'a self) -> Result<&'a T> {
75+
(self.context as &dyn Any)
76+
.downcast_ref()
77+
.ok_or(Error::NoContext)
78+
}
5579
}

crates/rspack_cacheable/src/deserialize.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::any::Any;
2-
31
use rkyv::{
42
Archive, Deserialize, access,
53
api::{deserialize_using, high::HighValidator},
@@ -10,7 +8,7 @@ use rkyv::{
108
};
119

1210
use crate::{
13-
context::ContextGuard,
11+
context::{CacheableContext, ContextGuard},
1412
error::{Error, Result},
1513
};
1614

@@ -21,7 +19,7 @@ pub type Deserializer = Strategy<Pool, Error>;
2119
///
2220
/// This function implementation refers to rkyv::from_bytes and
2321
/// add custom error and context support
24-
pub fn from_bytes<T, C: Any>(bytes: &[u8], context: &C) -> Result<T>
22+
pub fn from_bytes<T, C: CacheableContext>(bytes: &[u8], context: &C) -> Result<T>
2523
where
2624
T: Archive,
2725
T::Archived: for<'a> CheckBytes<Validator<'a>> + Deserialize<T, Deserializer>,

crates/rspack_cacheable/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,20 @@ pub mod __private {
2929
#[cfg(not(feature = "noop"))]
3030
pub use deserialize::from_bytes;
3131
#[cfg(feature = "noop")]
32-
pub fn from_bytes<T, C: std::any::Any>(_bytes: &[u8], _context: &C) -> Result<T> {
32+
pub fn from_bytes<T, C: CacheableContext>(_bytes: &[u8], _context: &C) -> Result<T> {
3333
let _ = deserialize::from_bytes::<u8, u8>;
3434
panic!("Cannot use from_bytes when noop feature is enabled")
3535
}
3636

3737
#[cfg(not(feature = "noop"))]
3838
pub use serialize::to_bytes;
3939
#[cfg(feature = "noop")]
40-
pub fn to_bytes<T, C: std::any::Any>(_value: &T, _ctx: &C) -> Result<Vec<u8>> {
40+
pub fn to_bytes<T, C: CacheableContext>(_value: &T, _ctx: &C) -> Result<Vec<u8>> {
4141
let _ = serialize::to_bytes::<u8, u8>;
4242
panic!("Cannot use to_bytes when noop feature is enabled")
4343
}
4444

45+
pub use context::{CacheableContext, ContextGuard};
4546
pub use deserialize::{Deserializer, Validator};
4647
pub use error::{Error, Result};
4748
pub use serialize::Serializer;

crates/rspack_cacheable/src/serialize.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::any::Any;
2-
31
use rkyv::{
42
Serialize,
53
api::{high::HighSerializer, serialize_using},
@@ -12,7 +10,7 @@ use rkyv::{
1210
};
1311

1412
use crate::{
15-
context::ContextGuard,
13+
context::{CacheableContext, ContextGuard},
1614
error::{Error, Result},
1715
};
1816

@@ -22,7 +20,7 @@ pub type Serializer<'a> = HighSerializer<AlignedVec, ArenaHandle<'a>, Error>;
2220
///
2321
/// This function implementation refers to rkyv::to_bytes and
2422
/// add custom error and context support
25-
pub fn to_bytes<T, C: Any>(value: &T, ctx: &C) -> Result<Vec<u8>>
23+
pub fn to_bytes<T, C: CacheableContext>(value: &T, ctx: &C) -> Result<Vec<u8>>
2624
where
2725
T: for<'a> Serialize<Serializer<'a>>,
2826
{

crates/rspack_cacheable/src/with/as.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::any::Any;
2-
31
use rkyv::{
42
Archive, Archived, Deserialize, Place, Resolver, Serialize,
53
de::Pooling,
@@ -11,10 +9,10 @@ use rkyv::{
119
use crate::{Error, Result, context::ContextGuard};
1210

1311
pub trait AsConverter<T> {
14-
fn serialize(data: &T, ctx: &dyn Any) -> Result<Self>
12+
fn serialize(data: &T, guard: &ContextGuard) -> Result<Self>
1513
where
1614
Self: Sized;
17-
fn deserialize(self, ctx: &dyn Any) -> Result<T>;
15+
fn deserialize(self, guard: &ContextGuard) -> Result<T>;
1816
}
1917

2018
pub struct As<A> {
@@ -47,8 +45,8 @@ where
4745
{
4846
#[inline]
4947
fn serialize_with(field: &T, serializer: &mut S) -> Result<Self::Resolver> {
50-
let ctx = ContextGuard::sharing_context(serializer)?;
51-
let value = <A as AsConverter<T>>::serialize(field, ctx)?;
48+
let guard = ContextGuard::sharing_guard(serializer)?;
49+
let value = <A as AsConverter<T>>::serialize(field, guard)?;
5250
Ok(AsResolver {
5351
resolver: value.serialize(serializer)?,
5452
value,
@@ -65,7 +63,7 @@ where
6563
#[inline]
6664
fn deserialize_with(field: &Archived<A>, de: &mut D) -> Result<T> {
6765
let field = A::Archived::deserialize(field, de)?;
68-
let ctx = ContextGuard::pooling_context(de)?;
69-
field.deserialize(ctx)
66+
let guard = ContextGuard::pooling_guard(de)?;
67+
field.deserialize(guard)
7068
}
7169
}

crates/rspack_cacheable/src/with/custom.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::any::Any;
2-
31
use rkyv::{
42
Archive, Deserialize, Place, Serialize,
53
de::Pooling,
@@ -8,15 +6,15 @@ use rkyv::{
86
with::{ArchiveWith, DeserializeWith, SerializeWith},
97
};
108

11-
use crate::{Error, Result, cacheable, context::ContextGuard};
9+
use crate::{ContextGuard, Error, Result, cacheable};
1210

1311
/// A trait for writing custom serialization and deserialization.
1412
///
1513
/// `#[cacheable(with=Custom)]` will use this trait.
1614
pub trait CustomConverter {
1715
type Target: Archive;
18-
fn serialize(&self, ctx: &dyn Any) -> Result<Self::Target>;
19-
fn deserialize(data: Self::Target, ctx: &dyn Any) -> Result<Self>
16+
fn serialize(&self, guard: &ContextGuard) -> Result<Self::Target>;
17+
fn deserialize(data: Self::Target, guard: &ContextGuard) -> Result<Self>
2018
where
2119
Self: Sized;
2220
}
@@ -57,8 +55,8 @@ where
5755
{
5856
#[inline]
5957
fn serialize_with(field: &T, serializer: &mut S) -> Result<Self::Resolver> {
60-
let ctx = ContextGuard::sharing_context(serializer)?;
61-
let value = DataBox(T::serialize(field, ctx)?);
58+
let guard = ContextGuard::sharing_guard(serializer)?;
59+
let value = DataBox(T::serialize(field, guard)?);
6260
Ok(CustomResolver {
6361
resolver: value.serialize(serializer)?,
6462
value,
@@ -76,7 +74,7 @@ where
7674
#[inline]
7775
fn deserialize_with(field: &ArchivedDataBox<T::Target>, de: &mut D) -> Result<T> {
7876
let value = field.deserialize(de)?;
79-
let ctx = ContextGuard::pooling_context(de)?;
80-
T::deserialize(value.0, ctx)
77+
let guard = ContextGuard::pooling_guard(de)?;
78+
T::deserialize(value.0, guard)
8179
}
8280
}

crates/rspack_cacheable_test/tests/context.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use std::{any::Any, sync::Arc};
1+
use std::sync::Arc;
22

33
use rspack_cacheable::{
4-
Error, enable_cacheable as cacheable, from_bytes, to_bytes,
4+
CacheableContext, ContextGuard, Error, Result, enable_cacheable as cacheable, from_bytes,
5+
to_bytes,
56
with::{As, AsConverter},
67
};
78

@@ -15,17 +16,21 @@ struct Context {
1516
option: Arc<CompilerOptions>,
1617
}
1718

19+
impl CacheableContext for Context {
20+
fn project_root(&self) -> Option<&std::path::Path> {
21+
None
22+
}
23+
}
24+
1825
#[cacheable]
1926
struct FromContext;
2027

2128
impl AsConverter<Arc<CompilerOptions>> for FromContext {
22-
fn serialize(_data: &Arc<CompilerOptions>, _ctx: &dyn Any) -> Result<Self, Error> {
29+
fn serialize(_data: &Arc<CompilerOptions>, _guard: &ContextGuard) -> Result<Self> {
2330
Ok(FromContext)
2431
}
25-
fn deserialize(self, ctx: &dyn Any) -> Result<Arc<CompilerOptions>, Error> {
26-
let Some(ctx) = ctx.downcast_ref::<Context>() else {
27-
return Err(Error::MessageError("context not match"));
28-
};
32+
fn deserialize(self, guard: &ContextGuard) -> Result<Arc<CompilerOptions>> {
33+
let ctx = guard.downcast_context::<Context>()?;
2934
Ok(ctx.option.clone())
3035
}
3136
}
@@ -50,10 +55,15 @@ fn test_context() {
5055

5156
let bytes = to_bytes(&module, &()).unwrap();
5257

53-
assert!(matches!(
54-
from_bytes::<Module, ()>(&bytes, &()),
55-
Err(Error::MessageError("context not match"))
56-
));
58+
let result = from_bytes::<Module, ()>(&bytes, &());
59+
assert!(result.is_err(), "should fail when using wrong context");
60+
if let Err(e) = result {
61+
assert!(
62+
matches!(e, Error::NoContext),
63+
"expected NoContext but got: {:?}",
64+
e
65+
);
66+
}
5767
let new_module: Module = from_bytes(&bytes, &context).unwrap();
5868
assert_eq!(module, new_module);
5969
}

crates/rspack_cacheable_test/tests/macro/cacheable_dyn.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
use rspack_cacheable::{
2-
enable_cacheable as cacheable, enable_cacheable_dyn as cacheable_dyn, from_bytes, to_bytes,
2+
CacheableContext, enable_cacheable as cacheable, enable_cacheable_dyn as cacheable_dyn,
3+
from_bytes, to_bytes,
34
};
45

56
#[test]
67
#[cfg_attr(miri, ignore)]
78
fn test_cacheable_dyn_macro() {
89
struct Context;
10+
impl CacheableContext for Context {
11+
fn project_root(&self) -> Option<&std::path::Path> {
12+
None
13+
}
14+
}
915

1016
#[cacheable_dyn]
1117
trait Animal {
@@ -77,6 +83,11 @@ fn test_cacheable_dyn_macro() {
7783
#[cfg_attr(miri, ignore)]
7884
fn test_cacheable_dyn_macro_with_generics() {
7985
struct Context;
86+
impl CacheableContext for Context {
87+
fn project_root(&self) -> Option<&std::path::Path> {
88+
None
89+
}
90+
}
8091

8192
#[cacheable_dyn]
8293
trait Animal<T = ()>: Send + Sync

crates/rspack_cacheable_test/tests/macro/manual_cacheable_dyn.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
use rspack_cacheable::{r#dyn::VTablePtr, enable_cacheable as cacheable, from_bytes, to_bytes};
1+
use rspack_cacheable::{
2+
CacheableContext, r#dyn::VTablePtr, enable_cacheable as cacheable, from_bytes, to_bytes,
3+
};
24

35
#[test]
46
#[cfg_attr(miri, ignore)]
57
fn test_manual_cacheable_dyn_macro() {
68
struct Context;
9+
impl CacheableContext for Context {
10+
fn project_root(&self) -> Option<&std::path::Path> {
11+
None
12+
}
13+
}
714

815
trait Animal: rspack_cacheable::r#dyn::SerializeDyn {
916
fn color(&self) -> &str;

crates/rspack_cacheable_test/tests/macro/manual_cacheable_dyn_with_generics.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
use rspack_cacheable::{r#dyn::VTablePtr, enable_cacheable as cacheable, from_bytes, to_bytes};
1+
use rspack_cacheable::{
2+
CacheableContext, r#dyn::VTablePtr, enable_cacheable as cacheable, from_bytes, to_bytes,
3+
};
24

35
#[test]
46
#[cfg_attr(miri, ignore)]
57
fn test_manual_cacheable_dyn_macro_with_generics() {
68
struct Context;
9+
impl CacheableContext for Context {
10+
fn project_root(&self) -> Option<&std::path::Path> {
11+
None
12+
}
13+
}
714

815
trait Animal<T = ()>: rspack_cacheable::r#dyn::SerializeDyn {
916
fn color(&self) -> &str;

0 commit comments

Comments
 (0)