rspack_cacheable/
deserialize.rs

1use std::any::Any;
2
3use rkyv::{
4  access,
5  api::{deserialize_using, high::HighValidator},
6  bytecheck::CheckBytes,
7  de::Pool,
8  rancor::{BoxedError, Source, Strategy, Trace},
9  util::AlignedVec,
10  Archive, Deserialize,
11};
12
13use crate::context::ContextGuard;
14
15#[derive(Debug)]
16pub enum DeserializeError {
17  BoxedError(BoxedError),
18  MessageError(&'static str),
19  DynCheckBytesNotRegister,
20  NoContext,
21  UnsupportedField,
22}
23
24impl std::fmt::Display for DeserializeError {
25  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26    match self {
27      Self::BoxedError(error) => error.fmt(f),
28      Self::MessageError(msg) => {
29        write!(f, "{msg}")
30      }
31      Self::DynCheckBytesNotRegister => {
32        write!(f, "cacheable_dyn check bytes not register")
33      }
34      Self::NoContext => {
35        write!(f, "no context")
36      }
37      Self::UnsupportedField => {
38        write!(f, "unsupported field")
39      }
40    }
41  }
42}
43
44impl std::error::Error for DeserializeError {
45  fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
46    match self {
47      Self::BoxedError(error) => error.source(),
48      _ => None,
49    }
50  }
51}
52
53impl Trace for DeserializeError {
54  fn trace<R>(self, trace: R) -> Self
55  where
56    R: std::fmt::Debug + std::fmt::Display + Send + Sync + 'static,
57  {
58    Self::BoxedError(BoxedError::trace(BoxedError::new(self), trace))
59  }
60}
61
62impl Source for DeserializeError {
63  fn new<T: std::error::Error + Send + Sync + 'static>(source: T) -> Self {
64    Self::BoxedError(BoxedError::new(source))
65  }
66}
67
68pub type Validator<'a> = HighValidator<'a, DeserializeError>;
69pub type Deserializer = Strategy<Pool, DeserializeError>;
70
71/// Transform bytes to struct
72///
73/// This function implementation refers to rkyv::from_bytes and
74/// add custom error and context support
75pub fn from_bytes<T, C: Any>(bytes: &[u8], context: &C) -> Result<T, DeserializeError>
76where
77  T: Archive,
78  T::Archived: for<'a> CheckBytes<Validator<'a>> + Deserialize<T, Deserializer>,
79{
80  let guard = ContextGuard::new(context);
81  let mut deserializer = Pool::default();
82  guard.add_to_pooling(&mut deserializer)?;
83  // The `bytes` ptr address in miri will throw UnalignedPointer error in rkyv.
84  // AlignedVec will force aligned the ptr address.
85  // Refer code: https://github.com/rkyv/rkyv/blob/dabbc1fcf5052f141403b84493bddb74c44f9ba9/rkyv/src/validation/archive/validator.rs#L135
86  let mut aligned_vec = AlignedVec::<16>::new();
87  aligned_vec.extend_from_slice(bytes);
88  deserialize_using(
89    access::<T::Archived, DeserializeError>(&aligned_vec)?,
90    &mut deserializer,
91  )
92}