turbopack_core/
update_instruction.rs1use 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}