Skip to main content

libinject/
pipe.rs

1use spin::Mutex;
2#[cfg(unix)]
3use std::os::unix::io::FromRawFd;
4#[cfg(windows)]
5use std::os::windows::io::FromRawHandle;
6use std::{fs::File, io::Write, sync::LazyLock};
7
8use serde::Serialize;
9
10static PIPE_WRITER: LazyLock<Mutex<Option<File>>> = LazyLock::new(|| Mutex::new(None));
11
12pub fn init(pipe_id: usize) {
13    let pipe_writer = {
14        #[cfg(windows)]
15        {
16            unsafe { File::from_raw_handle(pipe_id as *mut std::ffi::c_void) }
17        }
18        #[cfg(unix)]
19        {
20            unsafe { File::from_raw_fd(pipe_id as i32) }
21        }
22    };
23    let mut w = PIPE_WRITER
24        .lock();
25    *w = Some(pipe_writer);
26}
27
28#[derive(Debug)]
29pub enum PipeError {
30    WriteError(std::io::Error),
31    SerialiseError(serde_json::Error),
32}
33
34impl From<std::io::Error> for PipeError {
35    fn from(value: std::io::Error) -> Self {
36        PipeError::WriteError(value)
37    }
38}
39
40impl From<serde_json::Error> for PipeError {
41    fn from(value: serde_json::Error) -> Self {
42        PipeError::SerialiseError(value)
43    }
44}
45
46/// Send a serializable object down the pipe to the parent process.
47/// Panics if:
48/// - Unable to get a lock on the PIPE_WRITER.
49/// - The pipe module has not first been initialised with `pipe::init`.
50/// - The implementation of Serialize panics.
51/// - The writer returns an `std::io::Error`.
52///
53/// See `try_send` for a version that does not panic in the event of a serialisation or io::Error.
54pub fn send<T: Serialize>(obj: &T) {
55    try_send(obj).expect("Serialisation or io::Error occurred. Use `pipe::try_send` instead.")
56}
57
58/// Try and send a serializable object down the pipe to the parent process.
59/// Panics if:
60/// - Unable to get a lock on the PIPE_WRITER.
61/// - The pipe module has not first been initialised with `pipe::init`.
62pub fn try_send<T: Serialize>(obj: &T) -> Result<(), PipeError> {
63    let mut binding = PIPE_WRITER
64        .lock();
65    let w = binding
66        .as_mut()
67        .expect("Pipe must be initialised (with pipe::init) before sending data.");
68    writeln!(
69        w,
70        "{}",
71        serde_json::to_string(obj).map_err(PipeError::from)?
72    )
73    .map_err(Into::into)
74}