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