swc_common/
cache.rs

1use std::ops::Deref;
2
3use once_cell::sync::OnceCell;
4
5/// Wrapper for [OnceCell] with support for [rkyv].
6#[derive(Clone, Debug)]
7pub struct CacheCell<T>(OnceCell<T>);
8
9impl<T> Deref for CacheCell<T> {
10    type Target = OnceCell<T>;
11
12    fn deref(&self) -> &Self::Target {
13        &self.0
14    }
15}
16
17impl<T> CacheCell<T> {
18    pub fn new() -> Self {
19        Self(OnceCell::new())
20    }
21}
22
23impl<T> From<T> for CacheCell<T> {
24    fn from(value: T) -> Self {
25        Self(OnceCell::from(value))
26    }
27}
28
29impl<T> Default for CacheCell<T> {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35#[cfg(feature = "rkyv-impl")]
36mod rkyv_impl {
37    use std::hint::unreachable_unchecked;
38
39    use rancor::Fallible;
40    use rkyv::{
41        munge::munge, option::ArchivedOption, traits::NoUndef, Archive, Deserialize, Place,
42        Serialize,
43    };
44
45    use super::*;
46
47    #[allow(dead_code)]
48    #[repr(u8)]
49    enum ArchivedOptionTag {
50        None,
51        Some,
52    }
53
54    // SAFETY: `ArchivedOptionTag` is `repr(u8)` and so always consists of a single
55    // well-defined byte.
56    unsafe impl NoUndef for ArchivedOptionTag {}
57
58    #[repr(C)]
59    struct ArchivedOptionVariantNone(ArchivedOptionTag);
60
61    #[repr(C)]
62    struct ArchivedOptionVariantSome<T>(ArchivedOptionTag, T);
63
64    impl<T: Archive> Archive for CacheCell<T> {
65        type Archived = ArchivedOption<T::Archived>;
66        type Resolver = Option<T::Resolver>;
67
68        fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
69            match resolver {
70                None => {
71                    let out = unsafe { out.cast_unchecked::<ArchivedOptionVariantNone>() };
72                    munge!(let ArchivedOptionVariantNone(tag) = out);
73                    tag.write(ArchivedOptionTag::None);
74                }
75                Some(resolver) => {
76                    let out =
77                        unsafe { out.cast_unchecked::<ArchivedOptionVariantSome<T::Archived>>() };
78                    munge!(let ArchivedOptionVariantSome(tag, out_value) = out);
79                    tag.write(ArchivedOptionTag::Some);
80
81                    let value = if let Some(value) = self.get() {
82                        value
83                    } else {
84                        unsafe {
85                            unreachable_unchecked();
86                        }
87                    };
88
89                    value.resolve(resolver, out_value);
90                }
91            }
92        }
93    }
94
95    impl<T: Serialize<S>, S: Fallible + ?Sized> Serialize<S> for CacheCell<T> {
96        fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
97            self.get()
98                .map(|value| value.serialize(serializer))
99                .transpose()
100        }
101    }
102
103    impl<T, D> Deserialize<CacheCell<T>, D> for ArchivedOption<T::Archived>
104    where
105        T: Archive,
106        T::Archived: Deserialize<T, D>,
107        D: Fallible + ?Sized,
108    {
109        fn deserialize(&self, deserializer: &mut D) -> Result<CacheCell<T>, D::Error> {
110            Ok(match self {
111                ArchivedOption::Some(value) => CacheCell::from(value.deserialize(deserializer)?),
112                ArchivedOption::None => CacheCell::new(),
113            })
114        }
115    }
116}