tinyshader 0.1.0

Rust bindings for tinyshader
Documentation
extern crate tinyshader_sys;

use std::ffi::{CStr, CString};
use tinyshader_sys::*;

pub use tinyshader_sys::TsShaderStage as ShaderStage;

pub struct CompilerOptions {
    options: *mut TsCompilerOptions,
}

impl CompilerOptions {
    pub fn new() -> Self {
        unsafe {
            Self {
                options: tsCompilerOptionsCreate(),
            }
        }
    }

    pub fn stage<'a>(&'a mut self, stage: ShaderStage) -> &'a mut Self {
        unsafe {
            tsCompilerOptionsSetStage(self.options, stage);
        }
        self
    }

    pub fn entry_point<'a>(&'a mut self, entry_point: &str) -> &'a mut Self {
        unsafe {
            let c_entry_point = CString::new(entry_point).unwrap();
            tsCompilerOptionsSetEntryPoint(
                self.options,
                c_entry_point.as_ptr(),
                c_entry_point.as_bytes().len(),
            );
        }
        self
    }

    pub fn source<'a>(&'a mut self, source: &str, path_opt: Option<&str>) -> &'a mut Self {
        unsafe {
            let c_source = CString::new(source).unwrap();

            if let Some(path) = path_opt {
                let c_path = CString::new(path).unwrap();
                tsCompilerOptionsSetSource(
                    self.options,
                    c_source.as_ptr(),
                    c_source.as_bytes().len(),
                    c_path.as_ptr(),
                    c_path.as_bytes().len(),
                );
            } else {
                tsCompilerOptionsSetSource(
                    self.options,
                    c_source.as_ptr(),
                    c_source.as_bytes().len(),
                    std::ptr::null(),
                    0,
                );
            }
        }
        self
    }

    pub fn include_path<'a>(&'a mut self, path: &str) -> &'a mut Self {
        unsafe {
            let c_path = CString::new(path).unwrap();
            tsCompilerOptionsAddIncludePath(
                self.options,
                c_path.as_ptr(),
                c_path.as_bytes().len(),
            );
        }
        self
    }

    pub fn compile(&self) -> Result<Vec<u8>, String> {
        unsafe {
            let output = tsCompile(self.options);
            let errors = tsCompilerOutputGetErrors(output);
            if !errors.is_null() {
                let c_errors = CStr::from_ptr(errors);
                let error_str = c_errors.to_str().unwrap().to_owned();
                tsCompilerOutputDestroy(output);
                return Err(error_str);
            }

            let mut spirv_size: usize = 0;
            let spirv_ptr: *const u8 = tsCompilerOutputGetSpirv(output, &mut spirv_size);

            let mut vec = Vec::<u8>::new();
            vec.reserve(spirv_size);
            vec.set_len(spirv_size);

            std::ptr::copy_nonoverlapping(spirv_ptr, vec.as_mut_ptr(), spirv_size);

            tsCompilerOutputDestroy(output);
            return Ok(vec);
        }
    }
}

impl Drop for CompilerOptions {
    fn drop(&mut self) {
        unsafe {
            tsCompilerOptionsDestroy(self.options);
        }
    }
}