2022-12-05 14:48:57 +11:00
|
|
|
//! The librashader error C API. (`libra_error_*`).
|
2022-12-04 10:32:10 +11:00
|
|
|
use std::any::Any;
|
2023-01-14 08:05:13 +11:00
|
|
|
use std::ffi::{c_char, CString};
|
2022-12-05 14:35:51 +11:00
|
|
|
use std::mem::MaybeUninit;
|
|
|
|
use std::ptr::NonNull;
|
2022-12-04 10:32:10 +11:00
|
|
|
use thiserror::Error;
|
|
|
|
|
2022-12-05 14:35:51 +11:00
|
|
|
/// The error type for librashader.
|
2022-12-04 10:32:10 +11:00
|
|
|
#[non_exhaustive]
|
|
|
|
#[derive(Error, Debug)]
|
|
|
|
pub enum LibrashaderError {
|
2022-12-05 14:35:51 +11:00
|
|
|
#[error("There was an unknown error.")]
|
|
|
|
UnknownError(Box<dyn Any + Send + 'static>),
|
2022-12-04 10:32:10 +11:00
|
|
|
#[error("The parameter was null or invalid.")]
|
|
|
|
InvalidParameter(&'static str),
|
2023-01-15 01:36:26 +11:00
|
|
|
#[error("The provided string was not valid UTF8.")]
|
|
|
|
InvalidString(#[from] std::str::Utf8Error),
|
2022-12-04 10:32:10 +11:00
|
|
|
#[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),
|
2023-01-03 10:22:52 +11:00
|
|
|
#[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),
|
2023-01-15 01:36:26 +11:00
|
|
|
#[error("The provided parameter name was invalid.")]
|
|
|
|
UnknownShaderParameter(*const c_char),
|
2022-12-05 14:35:51 +11:00
|
|
|
#[cfg(feature = "runtime-opengl")]
|
2022-12-04 10:32:10 +11:00
|
|
|
#[error("There was an error in the OpenGL filter chain.")]
|
|
|
|
OpenGlFilterError(#[from] librashader::runtime::gl::error::FilterChainError),
|
2022-12-05 15:54:47 +11:00
|
|
|
#[cfg(feature = "runtime-d3d11")]
|
|
|
|
#[error("There was an error in the D3D11 filter chain.")]
|
|
|
|
D3D11FilterError(#[from] librashader::runtime::d3d11::error::FilterChainError),
|
2023-01-14 09:59:22 +11:00
|
|
|
#[cfg(feature = "runtime-vulkan")]
|
|
|
|
#[error("There was an error in the Vulkan filter chain.")]
|
|
|
|
VulkanFilterError(#[from] librashader::runtime::vk::error::FilterChainError),
|
2022-12-05 14:35:51 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Error codes for librashader error types.
|
|
|
|
#[repr(i32)]
|
|
|
|
pub enum LIBRA_ERRNO {
|
|
|
|
UNKNOWN_ERROR = 0,
|
|
|
|
INVALID_PARAMETER = 1,
|
2023-01-15 01:36:26 +11:00
|
|
|
INVALID_STRING = 2,
|
2022-12-05 14:35:51 +11:00
|
|
|
PRESET_ERROR = 3,
|
|
|
|
PREPROCESS_ERROR = 4,
|
2023-01-15 01:36:26 +11:00
|
|
|
SHADER_PARAMETER_ERROR = 5,
|
|
|
|
REFLECT_ERROR = 6,
|
|
|
|
RUNTIME_ERROR = 7,
|
2022-12-05 14:35:51 +11:00
|
|
|
}
|
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
// Nothing here can use extern_fn because they are lower level than libra_error_t.
|
|
|
|
|
2023-01-14 10:10:09 +11:00
|
|
|
/// Function pointer definition for libra_error_errno
|
2023-01-14 08:05:13 +11:00
|
|
|
pub type PFN_libra_error_errno = extern "C" fn(error: libra_error_t) -> LIBRA_ERRNO;
|
2022-12-05 14:35:51 +11:00
|
|
|
#[no_mangle]
|
|
|
|
/// Get the error code corresponding to this error object.
|
|
|
|
///
|
|
|
|
/// ## Safety
|
|
|
|
/// - `error` must be valid and initialized.
|
|
|
|
pub extern "C" fn libra_error_errno(error: libra_error_t) -> LIBRA_ERRNO {
|
|
|
|
let Some(error) = error else {
|
|
|
|
return LIBRA_ERRNO::UNKNOWN_ERROR
|
|
|
|
};
|
|
|
|
|
2022-12-05 16:06:37 +11:00
|
|
|
unsafe { error.as_ref().get_code() }
|
2022-12-05 14:35:51 +11:00
|
|
|
}
|
|
|
|
|
2023-01-14 10:10:09 +11:00
|
|
|
/// Function pointer definition for libra_error_print
|
2023-01-14 08:05:13 +11:00
|
|
|
pub type PFN_libra_error_print = extern "C" fn(error: libra_error_t) -> i32;
|
2022-12-05 14:35:51 +11:00
|
|
|
#[no_mangle]
|
|
|
|
/// Print the error message.
|
|
|
|
///
|
|
|
|
/// If `error` is null, this function does nothing and returns 1. Otherwise, this function returns 0.
|
|
|
|
/// ## Safety
|
|
|
|
/// - `error` must be a valid and initialized instance of `libra_error_t`.
|
|
|
|
pub 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}");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-01-14 10:10:09 +11:00
|
|
|
/// Function pointer definition for libra_error_free
|
2023-01-14 08:05:13 +11:00
|
|
|
pub type PFN_libra_error_free = extern "C" fn(error: *mut libra_error_t) -> i32;
|
2022-12-05 14:35:51 +11:00
|
|
|
#[no_mangle]
|
|
|
|
/// Frees any internal state kept by the error.
|
|
|
|
///
|
|
|
|
/// If `error` is null, this function does nothing and returns 1. Otherwise, this function returns 0.
|
|
|
|
/// The resulting error object becomes null.
|
|
|
|
/// ## Safety
|
|
|
|
/// - `error` must be null or a pointer to a valid and initialized instance of `libra_error_t`.
|
|
|
|
pub extern "C" fn libra_error_free(error: *mut libra_error_t) -> i32 {
|
|
|
|
if error.is_null() {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
let error = unsafe { &mut *error };
|
2022-12-05 14:35:51 +11:00
|
|
|
let error = error.take();
|
|
|
|
let Some(error) = error else {
|
|
|
|
return 1;
|
|
|
|
};
|
|
|
|
|
2022-12-05 16:06:37 +11:00
|
|
|
unsafe { drop(Box::from_raw(error.as_ptr())) }
|
2022-12-05 14:35:51 +11:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-01-14 10:10:09 +11:00
|
|
|
/// Function pointer definition for libra_error_write
|
2023-01-14 08:05:13 +11:00
|
|
|
pub type PFN_libra_error_write =
|
2023-01-14 16:27:35 +11:00
|
|
|
extern "C" fn(error: libra_error_t, out: *mut MaybeUninit<*mut c_char>) -> i32;
|
2022-12-05 14:35:51 +11:00
|
|
|
#[no_mangle]
|
|
|
|
/// Writes the error message into `out`
|
|
|
|
///
|
|
|
|
/// If `error` is null, this function does nothing and returns 1. Otherwise, this function returns 0.
|
|
|
|
/// ## Safety
|
|
|
|
/// - `error` must be a valid and initialized instance of `libra_error_t`.
|
|
|
|
/// - `out` must be a non-null pointer. The resulting string must not be modified.
|
2022-12-05 16:06:37 +11:00
|
|
|
pub extern "C" fn libra_error_write(
|
|
|
|
error: libra_error_t,
|
|
|
|
out: *mut MaybeUninit<*mut c_char>,
|
|
|
|
) -> i32 {
|
2022-12-05 14:35:51 +11:00
|
|
|
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()))
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-01-14 10:10:09 +11:00
|
|
|
/// Function pointer definition for libra_error_free_string
|
2023-01-14 08:05:13 +11:00
|
|
|
pub type PFN_libra_error_free_string = extern "C" fn(out: *mut *mut c_char) -> i32;
|
2022-12-05 14:35:51 +11:00
|
|
|
#[no_mangle]
|
|
|
|
/// Frees an error string previously allocated by `libra_error_write`.
|
|
|
|
///
|
|
|
|
/// After freeing, the pointer will be set to null.
|
|
|
|
/// ## Safety
|
|
|
|
/// - If `libra_error_write` is not null, it must point to a string previously returned by `libra_error_write`.
|
|
|
|
/// Attempting to free anything else, including strings or objects from other librashader functions, is immediate
|
|
|
|
/// Undefined Behaviour.
|
|
|
|
pub 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))
|
|
|
|
}
|
|
|
|
return 0;
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LibrashaderError {
|
2022-12-05 14:35:51 +11:00
|
|
|
pub(crate) const fn get_code(&self) -> LIBRA_ERRNO {
|
|
|
|
match self {
|
|
|
|
LibrashaderError::UnknownError(_) => LIBRA_ERRNO::UNKNOWN_ERROR,
|
|
|
|
LibrashaderError::InvalidParameter(_) => LIBRA_ERRNO::INVALID_PARAMETER,
|
2023-01-15 01:36:26 +11:00
|
|
|
LibrashaderError::InvalidString(_) => LIBRA_ERRNO::INVALID_STRING,
|
2022-12-05 14:35:51 +11:00
|
|
|
LibrashaderError::PresetError(_) => LIBRA_ERRNO::PRESET_ERROR,
|
|
|
|
LibrashaderError::PreprocessError(_) => LIBRA_ERRNO::PREPROCESS_ERROR,
|
2023-01-10 14:54:54 +11:00
|
|
|
LibrashaderError::ShaderCompileError(_) | LibrashaderError::ShaderReflectError(_) => {
|
2023-01-15 01:36:26 +11:00
|
|
|
LIBRA_ERRNO::REFLECT_ERROR
|
|
|
|
},
|
|
|
|
LibrashaderError::UnknownShaderParameter(_) => {
|
|
|
|
LIBRA_ERRNO::SHADER_PARAMETER_ERROR
|
2023-01-10 14:54:54 +11:00
|
|
|
}
|
2022-12-05 15:54:47 +11:00
|
|
|
#[cfg(feature = "runtime-opengl")]
|
|
|
|
LibrashaderError::OpenGlFilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
|
|
|
|
#[cfg(feature = "runtime-d3d11")]
|
2022-12-05 16:06:37 +11:00
|
|
|
LibrashaderError::D3D11FilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
|
2023-01-14 09:59:22 +11:00
|
|
|
#[cfg(feature = "runtime-vulkan")]
|
|
|
|
LibrashaderError::VulkanFilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
|
2022-12-05 14:35:51 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pub(crate) const fn ok() -> libra_error_t {
|
|
|
|
None
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
|
|
|
|
2022-12-05 14:35:51 +11:00
|
|
|
pub(crate) fn panic(panic: Box<dyn Any + Send + 'static>) -> libra_error_t {
|
2022-12-04 10:32:10 +11:00
|
|
|
LibrashaderError::UnknownError(panic).export()
|
|
|
|
}
|
|
|
|
|
2022-12-05 14:35:51 +11:00
|
|
|
pub(crate) fn export(self) -> libra_error_t {
|
|
|
|
NonNull::new(Box::into_raw(Box::new(self)))
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! assert_non_null {
|
|
|
|
($value:ident) => {
|
2023-01-14 16:27:35 +11:00
|
|
|
if $value.is_null() || !$value.is_aligned() {
|
2022-12-05 16:06:37 +11:00
|
|
|
return $crate::error::LibrashaderError::InvalidParameter(stringify!($value)).export();
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
2022-12-05 15:54:47 +11:00
|
|
|
};
|
|
|
|
(noexport $value:ident) => {
|
2023-01-14 16:27:35 +11:00
|
|
|
if $value.is_null() || !$value.is_aligned() {
|
2022-12-05 16:06:37 +11:00
|
|
|
return Err($crate::error::LibrashaderError::InvalidParameter(
|
|
|
|
stringify!($value),
|
|
|
|
));
|
2022-12-05 15:54:47 +11:00
|
|
|
}
|
2022-12-05 16:06:37 +11:00
|
|
|
};
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
2023-01-14 08:05:13 +11:00
|
|
|
|
|
|
|
// macro_rules! assert_some {
|
|
|
|
// ($value:ident) => {
|
|
|
|
// if $value.is_none() {
|
|
|
|
// return $crate::error::LibrashaderError::InvalidParameter(stringify!($value)).export();
|
|
|
|
// }
|
|
|
|
// };
|
|
|
|
// }
|
2022-12-04 10:32:10 +11:00
|
|
|
|
2022-12-04 11:55:27 +11:00
|
|
|
macro_rules! assert_some_ptr {
|
|
|
|
($value:ident) => {
|
|
|
|
if $value.is_none() {
|
2022-12-05 16:06:37 +11:00
|
|
|
return $crate::error::LibrashaderError::InvalidParameter(stringify!($value)).export();
|
2022-12-04 11:55:27 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
let $value = unsafe { $value.as_ref().unwrap().as_ref() };
|
|
|
|
};
|
|
|
|
(mut $value:ident) => {
|
|
|
|
if $value.is_none() {
|
2022-12-05 16:06:37 +11:00
|
|
|
return $crate::error::LibrashaderError::InvalidParameter(stringify!($value)).export();
|
2022-12-04 11:55:27 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
let $value = unsafe { $value.as_mut().unwrap().as_mut() };
|
2022-12-05 16:06:37 +11:00
|
|
|
};
|
2022-12-04 11:55:27 +11:00
|
|
|
}
|
|
|
|
|
2022-12-05 16:06:37 +11:00
|
|
|
use crate::ctypes::libra_error_t;
|
2022-12-04 10:32:10 +11:00
|
|
|
pub(crate) use assert_non_null;
|
2023-01-14 16:27:35 +11:00
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
// pub(crate) use assert_some;
|
2022-12-04 11:55:27 +11:00
|
|
|
pub(crate) use assert_some_ptr;
|