Skip to main content

objects/
observe.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Structured progress and warning channels for library callers.
3
4use std::{
5    borrow::Cow,
6    sync::{Mutex, MutexGuard},
7};
8
9/// Stable progress task identifier.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct TaskId(pub u64);
12
13/// Structured progress event emitted by long-running operations.
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum ProgressEvent {
16    Start {
17        id: TaskId,
18        label: Cow<'static, str>,
19        total: Option<u64>,
20    },
21    Advance {
22        id: TaskId,
23        delta: u64,
24    },
25    Message {
26        id: TaskId,
27        msg: Cow<'static, str>,
28    },
29    Finish {
30        id: TaskId,
31    },
32}
33
34/// Receives structured progress events.
35pub trait ProgressSink: Send + Sync {
36    fn event(&self, ev: ProgressEvent);
37}
38
39/// Receives structured warnings that should not be printed by domain crates.
40pub trait WarningSink: Send + Sync {
41    fn warn(&self, w: Warning);
42}
43
44/// Structured warning for embedders and render layers.
45#[derive(Debug, Clone, PartialEq, Eq)]
46pub struct Warning {
47    /// Stable machine-readable class, e.g. "refs_unlock_failed".
48    pub kind: Cow<'static, str>,
49    pub message: String,
50}
51
52/// Default progress sink for callers that do not care about progress.
53#[derive(Debug, Default, Clone, Copy)]
54pub struct NoopProgress;
55
56impl ProgressSink for NoopProgress {
57    fn event(&self, _ev: ProgressEvent) {}
58}
59
60/// Default warning sink for callers that do not care about warnings.
61#[derive(Debug, Default, Clone, Copy)]
62pub struct NoopWarnings;
63
64impl WarningSink for NoopWarnings {
65    fn warn(&self, _w: Warning) {}
66}
67
68/// Warning sink useful for embedders and tests that need to inspect warnings.
69#[derive(Debug, Default)]
70pub struct CollectingWarnings {
71    warnings: Mutex<Vec<Warning>>,
72}
73
74impl CollectingWarnings {
75    pub fn warnings(&self) -> Vec<Warning> {
76        self.guard().clone()
77    }
78
79    pub fn drain(&self) -> Vec<Warning> {
80        self.guard().drain(..).collect()
81    }
82
83    fn guard(&self) -> MutexGuard<'_, Vec<Warning>> {
84        match self.warnings.lock() {
85            Ok(guard) => guard,
86            Err(poisoned) => poisoned.into_inner(),
87        }
88    }
89}
90
91impl WarningSink for CollectingWarnings {
92    fn warn(&self, w: Warning) {
93        self.guard().push(w);
94    }
95}