1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::{
    io::{self, prelude::*, BufWriter},
    process::{Child, ChildStdin},
};

use bevy::{prelude::*, tasks::Task};

use crate::{Pid, ProcessOutputBuffer};

#[derive(Debug, Component)]
pub struct Process {
    pub(crate) process: Child,
    pub(crate) reader_task: Task<()>,
    pub(crate) output_buffer: ProcessOutputBuffer,
    pub(crate) stdin_writer: BufWriter<ChildStdin>,
}

impl Process {
    pub fn id(&self) -> Pid {
        self.process.id()
    }

    pub fn kill(&mut self) -> io::Result<()> {
        self.process.kill()
    }

    /// Write a string to the process stdin.
    ///
    /// See [`Process::println`] for a version which adds a newline (`\n`) to the end of the string.
    ///
    /// Here's how you can write "Hello world!" to a process that has just been started:
    ///
    /// ```
    /// # use bevy::prelude::*;
    /// # use bevy_local_commands::Process;
    /// fn provide_input(mut query: Query<&mut Process, Added<Process>>) {
    ///     for mut process in query.iter_mut() {
    ///         process.print("Hello world!").unwrap();
    ///     }
    /// }
    /// ```
    ///
    /// If you want more control, you can also use the `write!` macro.
    /// Just keep in mind that this might not flush the input buffer directly,
    /// so your process might receive the output later.
    /// You can also manually flush the buffer when you have written all your input.
    ///
    /// ```
    /// # use bevy::prelude::*;
    /// # use bevy_local_commands::Process;
    /// // To use the macro, we need to import `Write`
    /// use std::io::Write;
    ///
    /// fn provide_input(mut query: Query<&mut Process, Added<Process>>) {
    ///     for mut process in query.iter_mut() {
    ///         let name = "world";
    ///         write!(&mut process, "Hello {name}!").unwrap();
    ///         // Make sure that the process receives the input
    ///         process.flush().unwrap();
    ///     }
    /// }
    /// ```
    pub fn print(&mut self, input: &str) -> Result<(), io::Error> {
        self.write_all(input.as_bytes())?;
        self.flush()
    }

    /// Write a string, terminated by a newline (`\n`) to the process stdin.
    ///
    /// See [`Process::print`] for a version without the newline.
    ///
    /// Here's how you can write "Hello world!" to a process that has just been started:
    ///
    /// ```
    /// # use bevy::prelude::*;
    /// # use bevy_local_commands::Process;
    /// fn provide_input(mut query: Query<&mut Process, Added<Process>>) {
    ///     for mut process in query.iter_mut() {
    ///         process.println("Hello world!").unwrap();
    ///     }
    /// }
    /// ```
    ///
    /// If you want more control, you can also use the `writeln!` macro.
    /// Just keep in mind that this might not flush the input buffer directly,
    /// so your process might receive the output later.
    /// You can also manually flush the buffer when you have written all your input.
    ///
    /// ```
    /// # use bevy::prelude::*;
    /// # use bevy_local_commands::Process;
    /// // To use the macro, we need to import `Write`
    /// use std::io::Write;
    ///
    /// fn provide_input(mut query: Query<&mut Process, Added<Process>>) {
    ///     for mut process in query.iter_mut() {
    ///         let name = "world";
    ///         writeln!(&mut process, "Hello {name}!").unwrap();
    ///         // Make sure that the process receives the input
    ///         process.flush().unwrap();
    ///     }
    /// }
    /// ```
    pub fn println(&mut self, input: &str) -> Result<(), io::Error> {
        self.write_all(input.as_bytes())?;
        self.write_all(b"\n")?;
        self.flush()
    }
}

impl Write for Process {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stdin_writer.write(buf)
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.stdin_writer.write_all(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.stdin_writer.flush()
    }
}