Skip to main content

wasmer_types/
progress.rs

1//! Types used to report and handle compilation progress.
2
3use std::{borrow::Cow, fmt, num::NonZeroUsize, string::String, sync::Arc};
4use thiserror::Error;
5
6/// Indicates the current compilation progress.
7///
8/// All fields are kept private for forwards compatibility and future extension.
9/// Use the provided methods to access progress data.
10#[derive(Clone, Debug, Default)]
11pub struct CompilationProgress {
12    phase_name: Option<Cow<'static, str>>,
13    phase_step_count: Option<u64>,
14    phase_step: Option<u64>,
15}
16
17impl CompilationProgress {
18    /// Creates a new [`CompilationProgress`].
19    pub fn new(
20        phase_name: Option<Cow<'static, str>>,
21        phase_step_count: Option<u64>,
22        phase_step: Option<u64>,
23    ) -> Self {
24        Self {
25            phase_name,
26            phase_step_count,
27            phase_step,
28        }
29    }
30
31    /// Returns the name of the phase currently being executed.
32    pub fn phase_name(&self) -> Option<&str> {
33        self.phase_name.as_deref()
34    }
35
36    /// Returns the total number of steps in the current phase, if known.
37    pub fn phase_step_count(&self) -> Option<u64> {
38        self.phase_step_count
39    }
40
41    /// Returns the index of the current step within the phase, if known.
42    pub fn phase_step(&self) -> Option<u64> {
43        self.phase_step
44    }
45}
46
47/// Error returned when the user requests to abort an expensive computation.
48#[derive(Clone, Debug, Error)]
49#[error("{reason}")]
50pub struct UserAbort {
51    reason: String,
52}
53
54impl UserAbort {
55    /// Creates a new [`UserAbort`].
56    pub fn new(reason: impl Into<String>) -> Self {
57        Self {
58            reason: reason.into(),
59        }
60    }
61
62    /// Returns the configured reason.
63    pub fn reason(&self) -> &str {
64        &self.reason
65    }
66}
67
68type ProgressCallback =
69    dyn Fn(CompilationProgress) -> Result<(), UserAbort> + Send + Sync + 'static;
70type ReserveSizeCallbackFn = dyn Fn(usize) -> Result<(), UserAbort> + Send + Sync + 'static;
71
72#[derive(Clone)]
73struct ReserveSizeCallback {
74    callback: Arc<ReserveSizeCallbackFn>,
75    chunk_size: NonZeroUsize,
76}
77
78/// Wraps callbacks that can receive compilation progress and output-size notifications.
79#[derive(Clone)]
80pub struct CompilationProgressCallback {
81    callback: Arc<ProgressCallback>,
82    reserve_size_callback: Option<ReserveSizeCallback>,
83}
84
85impl CompilationProgressCallback {
86    /// Create a new callback wrapper.
87    ///
88    /// The provided callback will be invoked with progress updates during the compilation process,
89    /// and has to return a `Result<(), UserAbort>`.
90    ///
91    /// If the callback returns an error, the compilation will be aborted with a `CompileError::Aborted`.
92    pub fn new<F>(callback: F) -> Self
93    where
94        F: Fn(CompilationProgress) -> Result<(), UserAbort> + Send + Sync + 'static,
95    {
96        Self {
97            callback: Arc::new(callback),
98            reserve_size_callback: None,
99        }
100    }
101
102    /// Configures a callback for reporting increases in compilation output size.
103    ///
104    /// Singlepass uses this callback to account for emitted native-code bytes, reporting after
105    /// at least `chunk_size` bytes.
106    pub fn with_reserve_size_callback<F>(mut self, callback: F, chunk_size: NonZeroUsize) -> Self
107    where
108        F: Fn(usize) -> Result<(), UserAbort> + Send + Sync + 'static,
109    {
110        self.reserve_size_callback = Some(ReserveSizeCallback {
111            callback: Arc::new(callback),
112            chunk_size,
113        });
114        self
115    }
116
117    /// Returns the configured reserve-size reporting chunk size.
118    pub fn reserve_size_chunk_size(&self) -> Option<NonZeroUsize> {
119        self.reserve_size_callback
120            .as_ref()
121            .map(|callback| callback.chunk_size)
122    }
123
124    /// Reports an increase in compilation output size, in bytes.
125    ///
126    /// This is a no-op when no reserve-size callback was configured.
127    pub fn reserve_size(&self, size_increase: usize) -> Result<(), UserAbort> {
128        match &self.reserve_size_callback {
129            Some(callback) => (callback.callback)(size_increase),
130            None => Ok(()),
131        }
132    }
133
134    /// Notify the callback about new progress information.
135    pub fn notify(&self, progress: CompilationProgress) -> Result<(), UserAbort> {
136        (self.callback)(progress)
137    }
138}
139
140impl fmt::Debug for CompilationProgressCallback {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        f.debug_struct("CompilationProgressCallback").finish()
143    }
144}