genfut 0.5.0

Generate bindings for Futhark
Documentation
use regex::Regex;
use std::fmt::Write;

fn array_dim_expansion(n: usize) -> String {
    let mut buffer = String::new();
    for i in 0..n {
        writeln!(&mut buffer, "dim[{}],", i).expect("Write failed!");
    }
    buffer
}

fn ctor_array_type(t: &str, dim: usize) -> String {
    format!("Array_{}_{}d", t, dim)
}

fn gen_specific_type(input: &str) -> String {
    let re_array_type = Regex::new(r"futhark_(.+)_(\d+)d").unwrap();
    let captures = re_array_type.captures(input).unwrap();
    let dim: usize = captures[2].parse().unwrap();
    let ftype = &captures[1];
    let arr_type = ctor_array_type(ftype, dim);
    let oftype = format!("futhark_{}_{}d", ftype, dim);
    format!(
        include_str!("static/static_array_types.rs"),
        array_type = arr_type,
        futhark_type = oftype,
        dim = dim,
        inner_type = ftype
    )
}

fn gen_impl_futhark_type(input: &str) -> String {
    let re_array_type = Regex::new(r"futhark_(.+)_(\d+)d").unwrap();
    let captures = re_array_type.captures(input).unwrap();
    let dim: usize = captures[2].parse().unwrap();
    let mut buffer = String::new();
    let arr_type = ctor_array_type(&captures[1], dim);
    write!(&mut buffer,
r#"
impl futhark_{rust_type}_{dim}d {{
   unsafe fn new<C>(ctx: C, arr: &[{rust_type}], dim: &[i64]) -> *const Self
   where C: Into<*mut bindings::futhark_context>
   {{
     let ctx = ctx.into();
     bindings::futhark_new_{rust_type}_{dim}d(
       ctx,
       arr.as_ptr() as *mut {rust_type},
       {array_dim})
     }}
}}

impl FutharkType for futhark_{rust_type}_{dim}d {{
   type RustType = {rust_type};
   const DIM: usize = {dim};

    unsafe fn shape<C>(ctx: C, ptr: *const bindings::futhark_{rust_type}_{dim}d) -> *const i64
    where C: Into<*mut bindings::futhark_context>
    {{
        let ctx = ctx.into();
        bindings::futhark_shape_{rust_type}_{dim}d(ctx, ptr as *mut bindings::futhark_{rust_type}_{dim}d)
    }}
    unsafe fn values<C>(ctx: C, ptr: *mut Self, dst: *mut Self::RustType) -> Result<()>
    where C: Into<*mut bindings::futhark_context>
    {{
        let ctx = ctx.into();
        let ret = bindings::futhark_values_{rust_type}_{dim}d(ctx, ptr, dst);
        if ret != 0 {{
            return Err(crate::FutharkError::new(ctx).into());
        }} 
        // Sync the values to the array.
        bindings::futhark_context_sync(ctx);
        Ok(())
    }}
    unsafe fn free<C>(ctx: C, ptr: *mut Self) -> ::std::os::raw::c_int
    where C: Into<*mut bindings::futhark_context>
    {{
        let ctx = ctx.into();
        bindings::futhark_free_{rust_type}_{dim}d(ctx, ptr)
    }}}}"#, rust_type=captures[1].to_owned(), dim=dim, array_dim=array_dim_expansion(dim)
    ).expect("Write failed!");
    buffer
}

pub(crate) fn gen_impl_futhark_types(input: &Vec<String>) -> String {
    let mut buffer = String::new();
    let mut buffer2 = String::new();
    writeln!(&mut buffer, "use crate::bindings::*;").expect("Write failed!");
    for t in input {
        writeln!(&mut buffer, "{}", gen_impl_futhark_type(t)).expect("Write failed!");
        writeln!(&mut buffer2, "{}", gen_specific_type(t)).expect("Write failed!");
    }
    writeln!(&mut buffer, "{}", buffer2).expect("Write failed!");
    buffer
}