use std::any::Any;
use std::ffi::{c_char, CString};
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use thiserror::Error;
#[non_exhaustive]
#[derive(Error, Debug)]
pub enum LibrashaderError {
#[error("There was an unknown error.")]
UnknownError(Box<dyn Any + Send + 'static>),
#[error("The parameter was null or invalid.")]
InvalidParameter(&'static str),
#[error("The provided string was not valid UTF8.")]
InvalidString(#[from] std::str::Utf8Error),
#[error("There was an error parsing the preset.")]
PresetError(#[from] librashader::presets::ParsePresetError),
#[error("There was an error preprocessing the shader source.")]
PreprocessError(#[from] librashader::preprocess::PreprocessError),
#[error("There was an error compiling the shader source.")]
ShaderCompileError(#[from] librashader::reflect::ShaderCompileError),
#[error("There was an error reflecting the shader source.")]
ShaderReflectError(#[from] librashader::reflect::ShaderReflectError),
#[error("The provided parameter name was invalid.")]
UnknownShaderParameter(*const c_char),
#[cfg(feature = "runtime-opengl")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "runtime-opengl")))]
#[error("There was an error in the OpenGL filter chain.")]
OpenGlFilterError(#[from] librashader::runtime::gl::error::FilterChainError),
#[cfg(all(target_os = "windows", feature = "runtime-d3d11"))]
#[cfg_attr(
feature = "docsrs",
doc(cfg(all(target_os = "windows", feature = "runtime-d3d11")))
)]
#[error("There was an error in the D3D11 filter chain.")]
D3D11FilterError(#[from] librashader::runtime::d3d11::error::FilterChainError),
#[cfg(all(target_os = "windows", feature = "runtime-d3d12"))]
#[cfg_attr(
feature = "docsrs",
doc(cfg(all(target_os = "windows", feature = "runtime-d3d12")))
)]
#[error("There was an error in the D3D12 filter chain.")]
D3D12FilterError(#[from] librashader::runtime::d3d12::error::FilterChainError),
#[cfg(all(target_os = "windows", feature = "runtime-d3d9"))]
#[cfg_attr(
feature = "docsrs",
doc(cfg(all(target_os = "windows", feature = "runtime-d3d9")))
)]
#[error("There was an error in the D3D9 filter chain.")]
D3D9FilterError(#[from] librashader::runtime::d3d9::error::FilterChainError),
#[cfg(feature = "runtime-vulkan")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "runtime-vulkan")))]
#[error("There was an error in the Vulkan filter chain.")]
VulkanFilterError(#[from] librashader::runtime::vk::error::FilterChainError),
#[cfg_attr(
feature = "docsrs",
doc(cfg(all(target_vendor = "apple", feature = "runtime-metal")))
)]
#[cfg(all(target_vendor = "apple", feature = "runtime-metal"))]
#[error("There was an error in the Metal filter chain.")]
MetalFilterError(#[from] librashader::runtime::mtl::error::FilterChainError),
#[error("This error is not reachable")]
Infallible(#[from] std::convert::Infallible),
}
#[repr(i32)]
pub enum LIBRA_ERRNO {
UNKNOWN_ERROR = 0,
INVALID_PARAMETER = 1,
INVALID_STRING = 2,
PRESET_ERROR = 3,
PREPROCESS_ERROR = 4,
SHADER_PARAMETER_ERROR = 5,
REFLECT_ERROR = 6,
RUNTIME_ERROR = 7,
LUT_LOAD_ERROR = 8,
COMPILE_ERROR = 9,
}
pub type PFN_libra_error_errno = extern "C" fn(error: libra_error_t) -> LIBRA_ERRNO;
#[no_mangle]
pub unsafe extern "C" fn libra_error_errno(error: libra_error_t) -> LIBRA_ERRNO {
let Some(error) = error else {
return LIBRA_ERRNO::UNKNOWN_ERROR;
};
unsafe {
let code = error.as_ref().get_code();
if matches!(code, LIBRA_ERRNO::RUNTIME_ERROR) {
error.as_ref().get_runtime_code()
} else {
code
}
}
}
pub type PFN_libra_error_print = extern "C" fn(error: libra_error_t) -> i32;
#[no_mangle]
pub unsafe extern "C" fn libra_error_print(error: libra_error_t) -> i32 {
let Some(error) = error else { return 1 };
unsafe {
let error = error.as_ref();
println!("{error:?}: {error}");
}
0
}
pub type PFN_libra_error_free = extern "C" fn(error: *mut libra_error_t) -> i32;
#[no_mangle]
pub unsafe extern "C" fn libra_error_free(error: *mut libra_error_t) -> i32 {
if error.is_null() {
return 1;
}
let error = unsafe { &mut *error };
let error = error.take();
let Some(error) = error else {
return 1;
};
unsafe { drop(Box::from_raw(error.as_ptr())) }
0
}
pub type PFN_libra_error_write =
extern "C" fn(error: libra_error_t, out: *mut MaybeUninit<*mut c_char>) -> i32;
#[no_mangle]
pub unsafe extern "C" fn libra_error_write(
error: libra_error_t,
out: *mut MaybeUninit<*mut c_char>,
) -> i32 {
let Some(error) = error else { return 1 };
if out.is_null() {
return 1;
}
unsafe {
let error = error.as_ref();
let Ok(cstring) = CString::new(format!("{error:?}: {error}")) else {
return 1;
};
out.write(MaybeUninit::new(cstring.into_raw()))
}
0
}
pub type PFN_libra_error_free_string = extern "C" fn(out: *mut *mut c_char) -> i32;
#[no_mangle]
pub unsafe extern "C" fn libra_error_free_string(out: *mut *mut c_char) -> i32 {
if out.is_null() {
return 1;
}
unsafe {
let ptr = out.read();
*out = std::ptr::null_mut();
drop(CString::from_raw(ptr))
}
0
}
impl LibrashaderError {
pub(crate) const fn get_code(&self) -> LIBRA_ERRNO {
match self {
LibrashaderError::UnknownError(_) => LIBRA_ERRNO::UNKNOWN_ERROR,
LibrashaderError::InvalidParameter(_) => LIBRA_ERRNO::INVALID_PARAMETER,
LibrashaderError::InvalidString(_) => LIBRA_ERRNO::INVALID_STRING,
LibrashaderError::PresetError(_) => LIBRA_ERRNO::PRESET_ERROR,
LibrashaderError::PreprocessError(_) => LIBRA_ERRNO::PREPROCESS_ERROR,
LibrashaderError::ShaderCompileError(_) | LibrashaderError::ShaderReflectError(_) => {
LIBRA_ERRNO::REFLECT_ERROR
}
LibrashaderError::UnknownShaderParameter(_) => LIBRA_ERRNO::SHADER_PARAMETER_ERROR,
#[cfg(feature = "runtime-opengl")]
LibrashaderError::OpenGlFilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
#[cfg(all(target_os = "windows", feature = "runtime-d3d11"))]
LibrashaderError::D3D11FilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
#[cfg(all(target_os = "windows", feature = "runtime-d3d12"))]
LibrashaderError::D3D12FilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
#[cfg(all(target_os = "windows", feature = "runtime-d3d9"))]
LibrashaderError::D3D9FilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
#[cfg(feature = "runtime-vulkan")]
LibrashaderError::VulkanFilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
#[cfg(all(target_vendor = "apple", feature = "runtime-metal"))]
LibrashaderError::MetalFilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
LibrashaderError::Infallible(_) => LIBRA_ERRNO::UNKNOWN_ERROR,
}
}
pub(crate) const fn get_runtime_code(&self) -> LIBRA_ERRNO {
match self {
#[cfg(feature = "runtime-opengl")]
LibrashaderError::OpenGlFilterError(ogl) => match ogl {
librashader::runtime::gl::error::FilterChainError::FramebufferInit(_) => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::gl::error::FilterChainError::SpirvCrossReflectError(_) => {
LIBRA_ERRNO::REFLECT_ERROR
}
librashader::runtime::gl::error::FilterChainError::ShaderPresetError(_) => {
LIBRA_ERRNO::PRESET_ERROR
}
librashader::runtime::gl::error::FilterChainError::ShaderPreprocessError(_) => {
LIBRA_ERRNO::PREPROCESS_ERROR
}
librashader::runtime::gl::error::FilterChainError::ShaderCompileError(_)
| librashader::runtime::gl::error::FilterChainError::ShaderReflectError(_) => {
LIBRA_ERRNO::REFLECT_ERROR
}
librashader::runtime::gl::error::FilterChainError::LutLoadError(_) => {
LIBRA_ERRNO::LUT_LOAD_ERROR
}
librashader::runtime::gl::error::FilterChainError::GLLoadError => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::gl::error::FilterChainError::GLLinkError(_)
| librashader::runtime::gl::error::FilterChainError::GlCompileError(_)
| librashader::runtime::gl::error::FilterChainError::GlProgramError(_) => {
LIBRA_ERRNO::COMPILE_ERROR
}
librashader::runtime::gl::error::FilterChainError::GlSamplerError
| librashader::runtime::gl::error::FilterChainError::GlInvalidFramebuffer
| librashader::runtime::gl::error::FilterChainError::GlError(_) => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::gl::error::FilterChainError::Infallible(_) => {
LIBRA_ERRNO::UNKNOWN_ERROR
}
_ => LIBRA_ERRNO::RUNTIME_ERROR,
},
#[cfg(all(target_os = "windows", feature = "runtime-d3d11"))]
LibrashaderError::D3D11FilterError(d3d) => match d3d {
librashader::runtime::d3d11::error::FilterChainError::Direct3DOperationError(_)
| librashader::runtime::d3d11::error::FilterChainError::Direct3DError(_) => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::d3d11::error::FilterChainError::D3DCompileError(_) => {
LIBRA_ERRNO::COMPILE_ERROR
}
librashader::runtime::d3d11::error::FilterChainError::ShaderPresetError(_) => {
LIBRA_ERRNO::PRESET_ERROR
}
librashader::runtime::d3d11::error::FilterChainError::ShaderPreprocessError(_) => {
LIBRA_ERRNO::PREPROCESS_ERROR
}
librashader::runtime::d3d11::error::FilterChainError::ShaderCompileError(_)
| librashader::runtime::d3d11::error::FilterChainError::ShaderReflectError(_) => {
LIBRA_ERRNO::REFLECT_ERROR
}
librashader::runtime::d3d11::error::FilterChainError::LutLoadError(_) => {
LIBRA_ERRNO::LUT_LOAD_ERROR
}
_ => LIBRA_ERRNO::RUNTIME_ERROR,
},
#[cfg(all(target_os = "windows", feature = "runtime-d3d12"))]
LibrashaderError::D3D12FilterError(d3d) => match d3d {
librashader::runtime::d3d12::error::FilterChainError::Direct3DOperationError(_)
| librashader::runtime::d3d12::error::FilterChainError::Direct3DError(_) => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::d3d12::error::FilterChainError::ShaderPresetError(_) => {
LIBRA_ERRNO::PRESET_ERROR
}
librashader::runtime::d3d12::error::FilterChainError::ShaderPreprocessError(_) => {
LIBRA_ERRNO::PREPROCESS_ERROR
}
librashader::runtime::d3d12::error::FilterChainError::ShaderCompileError(_)
| librashader::runtime::d3d12::error::FilterChainError::ShaderReflectError(_) => {
LIBRA_ERRNO::REFLECT_ERROR
}
librashader::runtime::d3d12::error::FilterChainError::LutLoadError(_) => {
LIBRA_ERRNO::LUT_LOAD_ERROR
}
librashader::runtime::d3d12::error::FilterChainError::HeapError(_)
| librashader::runtime::d3d12::error::FilterChainError::AllocationError(_)
| librashader::runtime::d3d12::error::FilterChainError::InvalidDimensionError(_) => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::d3d12::error::FilterChainError::Infallible(_) => {
LIBRA_ERRNO::UNKNOWN_ERROR
}
_ => LIBRA_ERRNO::RUNTIME_ERROR,
},
#[cfg(all(target_os = "windows", feature = "runtime-d3d9"))]
LibrashaderError::D3D9FilterError(d3d) => match d3d {
librashader::runtime::d3d9::error::FilterChainError::Direct3DOperationError(_)
| librashader::runtime::d3d9::error::FilterChainError::Direct3DError(_) => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::d3d9::error::FilterChainError::ShaderPresetError(_) => {
LIBRA_ERRNO::PRESET_ERROR
}
librashader::runtime::d3d9::error::FilterChainError::ShaderPreprocessError(_) => {
LIBRA_ERRNO::PREPROCESS_ERROR
}
librashader::runtime::d3d9::error::FilterChainError::ShaderCompileError(_)
| librashader::runtime::d3d9::error::FilterChainError::ShaderReflectError(_) => {
LIBRA_ERRNO::REFLECT_ERROR
}
librashader::runtime::d3d9::error::FilterChainError::LutLoadError(_) => {
LIBRA_ERRNO::LUT_LOAD_ERROR
}
librashader::runtime::d3d9::error::FilterChainError::UniformNameError(_) => {
LIBRA_ERRNO::INVALID_STRING
}
_ => LIBRA_ERRNO::RUNTIME_ERROR,
},
#[cfg(feature = "runtime-vulkan")]
LibrashaderError::VulkanFilterError(vk) => match vk {
librashader::runtime::vk::error::FilterChainError::HandleIsNull => {
LIBRA_ERRNO::INVALID_PARAMETER
}
librashader::runtime::vk::error::FilterChainError::ShaderPresetError(_) => {
LIBRA_ERRNO::PRESET_ERROR
}
librashader::runtime::vk::error::FilterChainError::ShaderPreprocessError(_) => {
LIBRA_ERRNO::PREPROCESS_ERROR
}
librashader::runtime::vk::error::FilterChainError::ShaderCompileError(_)
| librashader::runtime::vk::error::FilterChainError::ShaderReflectError(_) => {
LIBRA_ERRNO::REFLECT_ERROR
}
librashader::runtime::vk::error::FilterChainError::LutLoadError(_) => {
LIBRA_ERRNO::LUT_LOAD_ERROR
}
librashader::runtime::vk::error::FilterChainError::VulkanResult(_)
| librashader::runtime::vk::error::FilterChainError::VulkanMemoryError(_)
| librashader::runtime::vk::error::FilterChainError::AllocationError(_)
| librashader::runtime::vk::error::FilterChainError::AllocationDoesNotExist => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::vk::error::FilterChainError::Infallible(_) => {
LIBRA_ERRNO::UNKNOWN_ERROR
}
_ => LIBRA_ERRNO::RUNTIME_ERROR,
},
#[cfg(all(target_vendor = "apple", feature = "runtime-metal"))]
LibrashaderError::MetalFilterError(mtl) => match mtl {
librashader::runtime::mtl::error::FilterChainError::ShaderPresetError(_) => {
LIBRA_ERRNO::PRESET_ERROR
}
librashader::runtime::mtl::error::FilterChainError::ShaderPreprocessError(_) => {
LIBRA_ERRNO::PREPROCESS_ERROR
}
librashader::runtime::mtl::error::FilterChainError::ShaderCompileError(_)
| librashader::runtime::mtl::error::FilterChainError::ShaderReflectError(_) => {
LIBRA_ERRNO::REFLECT_ERROR
}
librashader::runtime::mtl::error::FilterChainError::LutLoadError(_) => {
LIBRA_ERRNO::LUT_LOAD_ERROR
}
librashader::runtime::mtl::error::FilterChainError::SamplerError(_, _, _)
| librashader::runtime::mtl::error::FilterChainError::BufferError
| librashader::runtime::mtl::error::FilterChainError::MetalError(_)
| librashader::runtime::mtl::error::FilterChainError::ShaderWrongEntryName
| librashader::runtime::mtl::error::FilterChainError::FailedToCreateRenderPass
| librashader::runtime::mtl::error::FilterChainError::FailedToCreateTexture
| librashader::runtime::mtl::error::FilterChainError::FailedToCreateCommandBuffer => {
LIBRA_ERRNO::RUNTIME_ERROR
}
librashader::runtime::mtl::error::FilterChainError::Infallible(_) => {
LIBRA_ERRNO::UNKNOWN_ERROR
}
_ => LIBRA_ERRNO::RUNTIME_ERROR,
},
LibrashaderError::Infallible(_) => LIBRA_ERRNO::UNKNOWN_ERROR,
_ => self.get_code(),
}
}
pub(crate) const fn ok() -> libra_error_t {
None
}
pub(crate) fn export(self) -> libra_error_t {
NonNull::new(Box::into_raw(Box::new(self)))
}
}
macro_rules! assert_non_null {
(@EXPORT $value:ident) => {
if $value.is_null() || !$crate::ffi::ptr_is_aligned($value) {
return $crate::error::LibrashaderError::InvalidParameter(stringify!($value)).export();
}
};
($value:ident) => {
if $value.is_null() || !$crate::ffi::ptr_is_aligned($value) {
return Err($crate::error::LibrashaderError::InvalidParameter(
stringify!($value),
));
}
};
}
macro_rules! assert_some_ptr {
($value:ident) => {
if $value.is_none() {
return Err($crate::error::LibrashaderError::InvalidParameter(
stringify!($value),
));
}
let $value = unsafe { $value.as_ref().unwrap_unchecked().as_ref() };
};
(mut $value:ident) => {
if $value.is_none() {
return Err($crate::error::LibrashaderError::InvalidParameter(
stringify!($value),
));
}
let $value = unsafe { $value.as_mut().unwrap_unchecked().as_mut() };
};
}
use crate::ctypes::libra_error_t;
pub(crate) use assert_non_null;
pub(crate) use assert_some_ptr;