turbopack_core/diagnostics/
mod.rs1use std::cmp::Ordering;
2
3use anyhow::Result;
4use async_trait::async_trait;
5use auto_hash_map::AutoSet;
6use turbo_rcstr::RcStr;
7use turbo_tasks::{CollectiblesSource, FxIndexMap, ResolvedVc, Upcast, Vc, emit};
8
9#[turbo_tasks::value(serialization = "skip")]
10#[derive(Clone, Debug)]
11pub struct PlainDiagnostic {
12 pub category: RcStr,
13 pub name: RcStr,
14 pub payload: FxIndexMap<RcStr, RcStr>,
15}
16
17impl Ord for PlainDiagnostic {
18 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
19 self.name
20 .cmp(&other.name)
21 .then_with(|| self.category.cmp(&other.category))
22 .then_with(|| self.payload.len().cmp(&other.payload.len()))
23 .then_with(|| {
24 for ((a_key, a_value), (b_key, b_value)) in
25 self.payload.iter().zip(other.payload.iter())
26 {
27 match a_key.cmp(b_key) {
28 Ordering::Equal => {}
29 other => return other,
30 }
31 match a_value.cmp(b_value) {
32 Ordering::Equal => {}
33 other => return other,
34 }
35 }
36 Ordering::Equal
37 })
38 }
39}
40
41impl PartialOrd for PlainDiagnostic {
42 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
43 Some(self.cmp(other))
44 }
45}
46
47#[turbo_tasks::value(transparent)]
48pub struct DiagnosticPayload(
49 #[bincode(with = "turbo_bincode::indexmap")] pub FxIndexMap<RcStr, RcStr>,
50);
51
52#[turbo_tasks::value_trait]
54pub trait Diagnostic {
55 #[turbo_tasks::function]
60 fn category(&self) -> Vc<RcStr>;
61 #[turbo_tasks::function]
63 fn name(&self) -> Vc<RcStr>;
64 #[turbo_tasks::function]
66 fn payload(&self) -> Vc<DiagnosticPayload>;
67
68 #[turbo_tasks::function]
69 async fn into_plain(self: Vc<Self>) -> Result<Vc<PlainDiagnostic>> {
70 Ok(PlainDiagnostic {
71 category: self.category().owned().await?,
72 name: self.name().owned().await?,
73 payload: self.payload().owned().await?,
74 }
75 .cell())
76 }
77}
78
79pub trait DiagnosticExt {
80 fn emit(self);
81}
82
83impl<T> DiagnosticExt for ResolvedVc<T>
84where
85 T: Upcast<Box<dyn Diagnostic>>,
86{
87 fn emit(self) {
88 let diagnostic = ResolvedVc::upcast_non_strict::<Box<dyn Diagnostic>>(self);
89 emit(diagnostic);
90 }
91}
92
93#[async_trait]
94pub trait DiagnosticContextExt
95where
96 Self: Sized,
97{
98 async fn peek_diagnostics(self) -> Result<CapturedDiagnostics>;
99}
100
101#[async_trait]
102impl<T> DiagnosticContextExt for T
103where
104 T: CollectiblesSource + Copy + Send,
105{
106 async fn peek_diagnostics(self) -> Result<CapturedDiagnostics> {
107 Ok(CapturedDiagnostics {
108 diagnostics: self.peek_collectibles(),
109 })
110 }
111}
112
113#[derive(Debug)]
115#[turbo_tasks::value]
116pub struct CapturedDiagnostics {
117 pub diagnostics: AutoSet<ResolvedVc<Box<dyn Diagnostic>>>,
118}