Skip to main content

procwire_client/control/
stdio.rs

1//! Stdio I/O for control plane.
2//!
3//! The control plane uses stdio (stdin/stdout) for JSON-RPC communication.
4//! Currently only `$init` message is implemented.
5//!
6//! # Important
7//!
8//! - **stdout**: JSON-RPC messages (one per line)
9//! - **stderr**: Logs, debug output (not parsed by parent)
10//! - **Never use `println!`**: It may add `\r\n` on Windows
11//!
12//! # Example
13//!
14//! ```ignore
15//! use procwire_client::control::{write_stdout_line, build_init_message, InitSchema};
16//!
17//! let schema = InitSchema::new();
18//! let msg = build_init_message("/tmp/pipe.sock", &schema);
19//! write_stdout_line(&msg)?;
20//! ```
21
22use std::io::Write;
23
24/// Write a line to stdout (Control Plane).
25///
26/// Writes the string followed by a single `\n` and flushes.
27///
28/// # Important
29///
30/// - Uses explicit `\n`, NOT `println!` (which may add `\r\n` on Windows)
31/// - Flushes immediately (parent waits for complete line)
32/// - Any logging should go to stderr, not stdout
33///
34/// # Errors
35///
36/// Returns IO error if write or flush fails.
37pub fn write_stdout_line(line: &str) -> std::io::Result<()> {
38    let stdout = std::io::stdout();
39    let mut handle = stdout.lock();
40    handle.write_all(line.as_bytes())?;
41    handle.write_all(b"\n")?;
42    handle.flush()?;
43    Ok(())
44}
45
46/// Write a JSON value to stdout as a single line.
47///
48/// Serializes the value to JSON and writes it to stdout.
49///
50/// # Errors
51///
52/// Returns error if serialization or write fails.
53pub fn write_stdout_json<T: serde::Serialize>(value: &T) -> crate::error::Result<()> {
54    let json = serde_json::to_string(value)?;
55    write_stdout_line(&json)?;
56    Ok(())
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn test_write_stdout_line_does_not_panic() {
65        // We can't easily capture stdout in tests, but we can verify
66        // the function doesn't panic and returns Ok
67        let result = write_stdout_line(r#"{"test": true}"#);
68        assert!(result.is_ok());
69    }
70
71    #[test]
72    fn test_write_stdout_json_serializes() {
73        use serde::Serialize;
74
75        #[derive(Serialize)]
76        struct TestData {
77            value: i32,
78        }
79
80        let data = TestData { value: 42 };
81        let result = write_stdout_json(&data);
82        assert!(result.is_ok());
83    }
84}