resolc 0.3.0

Solidity frontend for the revive compiler
//! Process for compiling a single compilation unit using Web Workers.

use std::ffi::{c_char, c_void, CStr, CString};

use super::Input;
use super::Output;
use super::Process;

use anyhow::Context;
use serde::Deserialize;

#[derive(Deserialize)]
struct Error {
    message: String,
}

#[derive(Deserialize)]
struct Success {
    data: String,
}

#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
enum Response {
    Success(Success),
    Error(Error),
}

pub struct WorkerProcess;

impl Process for WorkerProcess {
    fn call(input: Input) -> anyhow::Result<Output> {
        let input_json = serde_json::to_vec(&input).expect("Always valid");
        let input_str = String::from_utf8(input_json).expect("Input shall be valid");
        // Prepare the input string for the Emscripten function
        let input_cstring = CString::new(input_str).expect("CString allocation failed");

        // Call the Emscripten function
        let output_ptr =
            unsafe { resolc_compile(input_cstring.as_ptr(), input_cstring.as_bytes().len()) };

        // Convert the output pointer back to a Rust string
        let output_str = unsafe {
            CStr::from_ptr(output_ptr)
                .to_str()
                .with_context(|| "Failed to convert C string to Rust string")
                .map(str::to_owned)
        };
        unsafe { libc::free(output_ptr as *mut c_void) };
        let output_str = output_str?;
        let response: Response = serde_json::from_str(&output_str)
            .map_err(|error| anyhow::anyhow!("Worker output parsing error: {}", error,))?;
        match response {
            Response::Success(out) => {
                let output: Output = revive_common::deserialize_from_slice(out.data.as_bytes())
                    .map_err(|error| {
                        anyhow::anyhow!("resolc.js subprocess output parsing error: {}", error,)
                    })?;

                Ok(output)
            }
            Response::Error(err) => anyhow::bail!("Worker error: {}", err.message,),
        }
    }
}

extern "C" {
    fn resolc_compile(input_ptr: *const c_char, input_len: usize) -> *const c_char;
}