idl 0.1.1

Library used for the idl language.
Documentation
use std::cell::RefCell;
use std::io::Write;
use std::process::{Command, Stdio};
use thiserror::Error;
use crate::language::*;

#[derive(Debug, Error)]
pub enum BinaryGenError {
    #[error("Json error `{0}`")]
    JsonError(String),
    #[error("Process creation")]
    ProcessCreation,
    #[error("Process error `{0}`")]
    ProcessError(String),
}

pub struct BinaryGen {
    child: RefCell<std::process::Child>,
}

impl BinaryGen {
    pub fn new(name: &str) -> Result<Self, BinaryGenError> {
        let mut cmd = Command::new(format!("idl_{}", name));

        cmd.stdin(Stdio::piped()).stdout(Stdio::piped());

        let child = cmd.spawn().map_err(|_| BinaryGenError::ProcessCreation)?;

        Ok(Self {
            child: RefCell::new(child),
        })
    }
}

impl IdlGen for BinaryGen {
    fn send_request(&self, request: LanguageRequest) -> anyhow::Result<LanguageResponse> {
        let mut child = self.child.borrow_mut();

        let request = serde_json::to_string(&request)
            .map_err(|err| BinaryGenError::JsonError(err.to_string()))?;

        let mut child_stdin = child.stdin.take().ok_or(BinaryGenError::ProcessCreation)?;
        let mut child_stdout = child.stdout.take().ok_or(BinaryGenError::ProcessCreation)?;

        let stdin_handle = std::thread::spawn(move || {
            let _ = child_stdin.write_all(request.as_bytes());
            request
        });

        let mut output = vec![];

        std::io::copy(&mut child_stdout, &mut output).unwrap();

        let status = child.wait().unwrap();
        let source = stdin_handle
            .join()
            .map_err(|_| BinaryGenError::ProcessCreation)?;

        let response = match String::from_utf8(output) {
            Ok(bindings) => match status.code() {
                Some(0) => bindings,
                _ => "".to_owned(),
            },
            _ => source,
        };

        let response: LanguageResponse = serde_json::from_str(&response).map_err(|err| {
            BinaryGenError::JsonError(format!("{}, response: {}", err.to_string(), response))
        })?;

        Ok(response)
    }
}