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 = "none")]
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]
55pub trait Diagnostic {
56 #[turbo_tasks::function]
63 fn category(&self) -> Vc<RcStr>;
64 #[turbo_tasks::function]
66 fn name(&self) -> Vc<RcStr>;
67 #[turbo_tasks::function]
69 fn payload(&self) -> Vc<DiagnosticPayload>;
70
71 #[turbo_tasks::function]
72 async fn into_plain(self: Vc<Self>) -> Result<Vc<PlainDiagnostic>> {
73 Ok(PlainDiagnostic {
74 category: self.category().owned().await?,
75 name: self.name().owned().await?,
76 payload: self.payload().owned().await?,
77 }
78 .cell())
79 }
80}
81
82pub trait DiagnosticExt {
83 fn emit(self);
84}
85
86impl<T> DiagnosticExt for ResolvedVc<T>
87where
88 T: Upcast<Box<dyn Diagnostic>>,
89{
90 fn emit(self) {
91 let diagnostic = ResolvedVc::upcast_non_strict::<Box<dyn Diagnostic>>(self);
92 emit(diagnostic);
93 }
94}
95
96#[async_trait]
97pub trait DiagnosticContextExt
98where
99 Self: Sized,
100{
101 async fn peek_diagnostics(self) -> Result<CapturedDiagnostics>;
102}
103
104#[async_trait]
105impl<T> DiagnosticContextExt for T
106where
107 T: CollectiblesSource + Copy + Send,
108{
109 async fn peek_diagnostics(self) -> Result<CapturedDiagnostics> {
110 Ok(CapturedDiagnostics {
111 diagnostics: self.peek_collectibles(),
112 })
113 }
114}
115
116#[derive(Debug)]
119#[turbo_tasks::value]
120pub struct CapturedDiagnostics {
121 pub diagnostics: AutoSet<ResolvedVc<Box<dyn Diagnostic>>>,
122}