Skip to main content

qubit_progress/reporter/impls/
writer_progress_reporter.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use std::{
11    io::Write,
12    sync::{
13        Arc,
14        Mutex,
15    },
16};
17
18use qubit_function::ArcConsumer;
19
20use super::human_readable_progress_reporter::HumanReadableProgressReporter;
21use crate::{
22    model::ProgressEvent,
23    reporter::ProgressReporter,
24};
25
26/// Progress reporter that writes human-readable metric snapshots to a writer.
27///
28/// One input event can produce multiple output lines: one line for each metric
29/// counter carried by the event.
30pub struct WriterProgressReporter<W> {
31    /// Shared writer receiving progress lines.
32    writer: Arc<Mutex<W>>,
33    /// Human-readable reporter that consumes formatted strings.
34    inner: HumanReadableProgressReporter,
35}
36
37impl<W> WriterProgressReporter<W> {
38    /// Returns the shared writer used by this reporter.
39    ///
40    /// # Returns
41    ///
42    /// A shared reference to the writer mutex.
43    #[inline]
44    pub const fn writer(&self) -> &Arc<Mutex<W>> {
45        &self.writer
46    }
47}
48
49impl<W> WriterProgressReporter<W>
50where
51    W: Write + Send + 'static,
52{
53    /// Creates a reporter from a shared writer.
54    ///
55    /// # Parameters
56    ///
57    /// * `writer` - Shared writer receiving progress output.
58    ///
59    /// # Returns
60    ///
61    /// A writer-backed progress reporter.
62    pub fn new(writer: Arc<Mutex<W>>) -> Self {
63        let consumer_writer = Arc::clone(&writer);
64        let consumer = ArcConsumer::new(move |line: &String| {
65            let mut writer = consumer_writer
66                .lock()
67                .unwrap_or_else(std::sync::PoisonError::into_inner);
68            writeln!(writer, "{line}").expect("progress reporter should write event");
69        });
70        Self {
71            writer,
72            inner: HumanReadableProgressReporter::new(consumer),
73        }
74    }
75
76    /// Creates a reporter from an owned writer.
77    ///
78    /// # Parameters
79    ///
80    /// * `writer` - Owned writer receiving progress output.
81    ///
82    /// # Returns
83    ///
84    /// A writer-backed progress reporter.
85    #[inline]
86    pub fn from_writer(writer: W) -> Self {
87        Self::new(Arc::new(Mutex::new(writer)))
88    }
89}
90
91impl<W> ProgressReporter for WriterProgressReporter<W>
92where
93    W: Write + Send + 'static,
94{
95    /// Writes one line for every metric snapshot in the event.
96    ///
97    /// # Parameters
98    ///
99    /// * `event` - Progress event to format and write.
100    ///
101    /// # Panics
102    ///
103    /// Recovers the inner writer when the writer mutex is poisoned, and panics
104    /// only when writing to the configured writer fails.
105    #[inline]
106    fn report(&self, event: &ProgressEvent) {
107        self.inner.report(event);
108    }
109}