Skip to main content

turbopack_core/
update_instruction.rs

1use std::{any::Any, fmt::Debug, sync::Arc};
2
3use serde::Serialize;
4use turbo_tasks::{
5    NonLocalValue,
6    debug::ValueDebugFormat,
7    trace::{TraceRawVcs, TraceRawVcsContext},
8};
9
10trait ErasedUpdateInstruction:
11    erased_serde::Serialize + Debug + Send + Sync + NonLocalValue + 'static
12{
13    fn as_any(&self) -> &dyn Any;
14    fn dyn_eq(&self, other: &dyn Any) -> bool;
15    fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext);
16}
17
18impl<T> ErasedUpdateInstruction for T
19where
20    T: Serialize + Eq + Debug + Send + Sync + NonLocalValue + TraceRawVcs + 'static,
21{
22    fn as_any(&self) -> &dyn Any {
23        self
24    }
25
26    fn dyn_eq(&self, other: &dyn Any) -> bool {
27        other.downcast_ref::<Self>() == Some(self)
28    }
29
30    fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
31        TraceRawVcs::trace_raw_vcs(self, trace_context);
32    }
33}
34
35erased_serde::serialize_trait_object!(ErasedUpdateInstruction);
36
37#[derive(Clone, Debug, Serialize, ValueDebugFormat, NonLocalValue)]
38#[serde(transparent)]
39pub struct UpdateInstruction(Arc<dyn ErasedUpdateInstruction>);
40
41impl PartialEq for UpdateInstruction {
42    fn eq(&self, other: &Self) -> bool {
43        self.0.dyn_eq(other.0.as_any())
44    }
45}
46
47impl Eq for UpdateInstruction {}
48
49impl UpdateInstruction {
50    pub fn new<T>(instruction: T) -> Self
51    where
52        T: Serialize + Eq + Debug + Send + Sync + NonLocalValue + TraceRawVcs + 'static,
53    {
54        Self(Arc::new(instruction))
55    }
56
57    pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
58        self.0.as_any().downcast_ref()
59    }
60}
61
62impl TraceRawVcs for UpdateInstruction {
63    fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
64        ErasedUpdateInstruction::trace_raw_vcs(self.0.as_ref(), trace_context);
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use serde::Serialize;
71    use turbo_tasks::{NonLocalValue, trace::TraceRawVcs};
72
73    use super::UpdateInstruction;
74
75    #[derive(Debug, PartialEq, Eq, Serialize, TraceRawVcs, NonLocalValue)]
76    struct TestInstruction {
77        value: u32,
78    }
79
80    #[test]
81    fn serializes_without_an_extra_wrapper() {
82        let instruction = UpdateInstruction::new(TestInstruction { value: 42 });
83
84        assert_eq!(
85            serde_json::to_value(&instruction).unwrap(),
86            serde_json::json!({ "value": 42 })
87        );
88    }
89
90    #[test]
91    fn downcasts_by_concrete_type() {
92        let instruction = UpdateInstruction::new(TestInstruction { value: 42 });
93
94        assert_eq!(
95            instruction
96                .downcast_ref::<TestInstruction>()
97                .map(|instruction| instruction.value),
98            Some(42)
99        );
100        assert_eq!(
101            instruction,
102            UpdateInstruction::new(TestInstruction { value: 42 })
103        );
104    }
105}