Skip to main content

dataprof_core/
progress.rs

1use std::fmt;
2use std::sync::Arc;
3use std::time::Duration;
4
5/// Structured progress events emitted by profiling engines.
6#[derive(Debug, Clone)]
7pub enum ProgressEvent {
8    /// Profiling has started. Emitted once before any data is processed.
9    Started {
10        estimated_total_rows: Option<usize>,
11        estimated_total_bytes: Option<u64>,
12    },
13    /// A chunk of rows has been processed.
14    ChunkProcessed {
15        rows_processed: usize,
16        bytes_consumed: u64,
17        elapsed: Duration,
18        processing_speed: f64,
19        percentage: Option<f64>,
20    },
21    /// Column schema has been detected (emitted once, after first chunk).
22    SchemaDetected { column_names: Vec<String> },
23    /// Profiling has finished (successfully or via early stop).
24    Finished {
25        total_rows: usize,
26        total_bytes: u64,
27        elapsed: Duration,
28        truncated: bool,
29    },
30    /// A non-fatal warning occurred during processing.
31    Warning { message: String },
32}
33
34/// How progress events are delivered to the consumer.
35///
36/// All variants are cheaply cloneable (`Arc` / channel `Sender`).
37#[derive(Clone, Default)]
38pub enum ProgressSink {
39    /// No progress reporting.
40    #[default]
41    None,
42    /// Synchronous callback (for Python bindings, tests, embedding, etc.)
43    Callback(Arc<dyn Fn(ProgressEvent) + Send + Sync>),
44    /// Async channel sender (requires `async-streaming` feature).
45    #[cfg(feature = "async-streaming")]
46    Channel(tokio::sync::mpsc::Sender<ProgressEvent>),
47}
48
49impl ProgressSink {
50    /// Whether events go anywhere.
51    pub fn is_active(&self) -> bool {
52        !matches!(self, Self::None)
53    }
54
55    /// Deliver one event. A full channel drops it rather than block profiling.
56    pub fn emit(&self, event: ProgressEvent) {
57        match self {
58            Self::None => {}
59            Self::Callback(callback) => callback(event),
60            #[cfg(feature = "async-streaming")]
61            Self::Channel(tx) => {
62                let _ = tx.try_send(event);
63            }
64        }
65    }
66}
67
68impl fmt::Debug for ProgressSink {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        match self {
71            Self::None => write!(f, "ProgressSink::None"),
72            Self::Callback(_) => write!(f, "ProgressSink::Callback(..)"),
73            #[cfg(feature = "async-streaming")]
74            Self::Channel(_) => write!(f, "ProgressSink::Channel(..)"),
75        }
76    }
77}