Skip to main content

osp_cli/app/
sink.rs

1//! Terminal-facing output sinks used by the host layer.
2//!
3//! This module exists so host entrypoints can emit stdout/stderr through a
4//! small abstraction that works both for the real terminal and for tests.
5//!
6//! Contract:
7//!
8//! - sinks are intentionally tiny and text-oriented
9//! - buffering, snapshotting, or process stdio forwarding belong here
10//! - higher-level rendering and message formatting belong elsewhere
11
12/// Terminal-facing output sink for stdout/stderr emission.
13pub trait UiSink {
14    /// Writes text to the sink's stdout channel.
15    fn write_stdout(&mut self, text: &str);
16
17    /// Writes text to the sink's stderr channel.
18    fn write_stderr(&mut self, text: &str);
19}
20
21/// Sink that forwards output directly to the process stdio streams.
22#[derive(Default)]
23pub struct StdIoUiSink;
24
25impl UiSink for StdIoUiSink {
26    fn write_stdout(&mut self, text: &str) {
27        if !text.is_empty() {
28            print!("{text}");
29        }
30    }
31
32    fn write_stderr(&mut self, text: &str) {
33        if !text.is_empty() {
34            eprint!("{text}");
35        }
36    }
37}
38
39/// Sink that buffers stdout and stderr for assertions and snapshot tests.
40///
41/// # Examples
42///
43/// ```
44/// use osp_cli::app::{BufferedUiSink, UiSink};
45///
46/// let mut sink = BufferedUiSink::default();
47/// sink.write_stdout("ok");
48/// sink.write_stderr("warn");
49///
50/// assert_eq!(sink.stdout, "ok");
51/// assert_eq!(sink.stderr, "warn");
52/// ```
53#[derive(Default, Debug)]
54pub struct BufferedUiSink {
55    /// Buffered stdout content in write order.
56    pub stdout: String,
57
58    /// Buffered stderr content in write order.
59    pub stderr: String,
60}
61
62impl UiSink for BufferedUiSink {
63    fn write_stdout(&mut self, text: &str) {
64        self.stdout.push_str(text);
65    }
66
67    fn write_stderr(&mut self, text: &str) {
68        self.stderr.push_str(text);
69    }
70}