use std::io::{Read, Write};
use std::os::unix::io::FromRawFd;
use std::thread::JoinHandle;
use super::{FileDescriptor, OsPipe};
pub struct StringStdioIn {
read_fd: FileDescriptor,
writer_thread: Option<JoinHandle<()>>,
}
impl StringStdioIn {
pub fn new(input: &str) -> Self {
let pipe = OsPipe::new().expect("failed to create pipe for StringStdioIn");
let data = input.to_string();
let write_fd = pipe.write_fd;
let writer_thread = std::thread::spawn(move || {
let mut file = unsafe { std::fs::File::from_raw_fd(write_fd.into_raw_fd()) };
let _ = file.write_all(data.as_bytes());
});
Self {
read_fd: pipe.read_fd,
writer_thread: Some(writer_thread),
}
}
pub fn fd(&self) -> FileDescriptor {
self.read_fd
}
pub fn join(mut self) {
self.read_fd.close();
self.read_fd = FileDescriptor::INVALID;
if let Some(handle) = self.writer_thread.take() {
let _ = handle.join();
}
}
}
impl Drop for StringStdioIn {
fn drop(&mut self) {
if let Some(handle) = self.writer_thread.take() {
self.read_fd.close();
let _ = handle.join();
} else {
self.read_fd.close();
}
}
}
pub struct StringStdioOut {
write_fd: FileDescriptor,
reader_thread: Option<JoinHandle<String>>,
}
impl StringStdioOut {
pub fn new() -> Self {
let pipe = OsPipe::new().expect("failed to create pipe for StringStdioOut");
let read_fd = pipe.read_fd;
let reader_thread = std::thread::spawn(move || {
let mut file = unsafe { std::fs::File::from_raw_fd(read_fd.into_raw_fd()) };
let mut output = String::new();
let _ = file.read_to_string(&mut output);
output
});
Self {
write_fd: pipe.write_fd,
reader_thread: Some(reader_thread),
}
}
pub fn fd(&self) -> FileDescriptor {
self.write_fd
}
pub fn collect(mut self) -> String {
self.write_fd.close();
self.write_fd = FileDescriptor::INVALID;
if let Some(handle) = self.reader_thread.take() {
handle.join().unwrap_or_default()
} else {
String::new()
}
}
}
impl Default for StringStdioOut {
fn default() -> Self {
Self::new()
}
}
impl Drop for StringStdioOut {
fn drop(&mut self) {
self.write_fd.close();
if let Some(handle) = self.reader_thread.take() {
let _ = handle.join();
}
}
}