use super::{Open, Sink}; use shell_words::split; use std::io::{self, Write}; use std::mem; use std::process::{Child, Command, Stdio}; use std::slice; pub struct SubprocessSink { shell_command: String, child: Option, } impl Open for SubprocessSink { fn open(shell_command: Option) -> SubprocessSink { if let Some(shell_command) = shell_command { SubprocessSink { shell_command: shell_command, child: None, } } else { panic!("subprocess sink requires specifying a shell command"); } } } impl Sink for SubprocessSink { fn start(&mut self) -> io::Result<()> { let args = split(&self.shell_command).unwrap(); self.child = Some( Command::new(&args[0]) .args(&args[1..]) .stdin(Stdio::piped()) .spawn()?, ); Ok(()) } fn stop(&mut self) -> io::Result<()> { if let Some(child) = &mut self.child.take() { child.kill()?; child.wait()?; } Ok(()) } fn write(&mut self, data: &[i16]) -> io::Result<()> { let data: &[u8] = unsafe { slice::from_raw_parts( data.as_ptr() as *const u8, data.len() * mem::size_of::(), ) }; if let Some(child) = &mut self.child { let child_stdin = child.stdin.as_mut().unwrap(); child_stdin.write_all(data)?; } Ok(()) } }