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()
}
}