use std::ffi::{CStr, CString, NulError};
use std::os::raw::{c_char, c_int, c_void};
use std::ptr::{self, NonNull};
use std::sync::atomic::{AtomicPtr, Ordering};
use std::{mem, panic, process};
use vapoursynth_sys as ffi;
use core::CoreRef;
#[derive(Debug, Clone, Copy)]
pub struct API {
handle: NonNull<ffi::VSAPI>,
}
unsafe impl Send for API {}
unsafe impl Sync for API {}
static RAW_API: AtomicPtr<ffi::VSAPI> = AtomicPtr::new(ptr::null_mut());
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum MessageType {
Debug,
Warning,
Critical,
Fatal,
}
macro_rules! prop_get_something {
($name:ident, $func:ident, $rv:ty) => (
#[inline]
pub(crate) unsafe fn $name(
self,
map: &ffi::VSMap,
key: *const c_char,
index: i32,
error: &mut i32,
) -> $rv {
(self.handle.as_ref().$func)(map, key, index, error)
}
)
}
macro_rules! prop_set_something {
($name:ident, $func:ident, $type:ty) => (
#[inline]
pub(crate) unsafe fn $name(
self,
map: &mut ffi::VSMap,
key: *const c_char,
value: $type,
append: ffi::VSPropAppendMode,
) -> i32 {
(self.handle.as_ref().$func)(map, key, value, append as i32)
}
)
}
#[cfg(feature = "gte-vapoursynth-api-36")]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct MessageHandlerId(ffi::VSMessageHandlerId);
impl API {
#[cfg(all(feature = "vsscript-functions", feature = "gte-vsscript-api-32"))]
#[inline]
pub fn get() -> Option<Self> {
use vsscript;
let handle = RAW_API.load(Ordering::Relaxed);
let handle = if handle.is_null() {
vsscript::maybe_initialize();
let handle =
unsafe { ffi::vsscript_getVSApi2(ffi::VAPOURSYNTH_API_VERSION) } as *mut ffi::VSAPI;
if !handle.is_null() {
RAW_API.store(handle, Ordering::Relaxed);
}
handle
} else {
handle
};
if handle.is_null() {
None
} else {
Some(Self {
handle: unsafe { NonNull::new_unchecked(handle) },
})
}
}
#[cfg(all(
feature = "vapoursynth-functions",
not(all(feature = "vsscript-functions", feature = "gte-vsscript-api-32"))
))]
#[inline]
pub fn get() -> Option<Self> {
let handle = RAW_API.load(Ordering::Relaxed);
let handle = if handle.is_null() {
let handle =
unsafe { ffi::getVapourSynthAPI(ffi::VAPOURSYNTH_API_VERSION) } as *mut ffi::VSAPI;
if !handle.is_null() {
RAW_API.store(handle, Ordering::Relaxed);
}
handle
} else {
handle
};
if handle.is_null() {
None
} else {
Some(Self {
handle: unsafe { NonNull::new_unchecked(handle) },
})
}
}
#[inline]
pub(crate) unsafe fn get_cached() -> Self {
Self {
handle: NonNull::new_unchecked(RAW_API.load(Ordering::Relaxed)),
}
}
#[inline]
pub(crate) unsafe fn set(handle: *const ffi::VSAPI) {
RAW_API.store(handle as *mut _, Ordering::Relaxed);
}
#[cfg(feature = "gte-vapoursynth-api-34")]
#[inline]
pub fn log(self, message_type: MessageType, message: &str) -> Result<(), NulError> {
let message = CString::new(message)?;
unsafe {
(self.handle.as_ref().logMessage)(message_type.ffi_type(), message.as_ptr());
}
Ok(())
}
#[inline]
#[cfg_attr(
feature = "gte-vapoursynth-api-36",
deprecated(note = "use `add_message_handler` and `remove_message_handler` instead")
)]
pub fn set_message_handler<F>(self, callback: F)
where
F: FnMut(MessageType, &CStr) + Send + 'static,
{
struct CallbackData {
callback: Box<dyn FnMut(MessageType, &CStr) + Send + 'static>,
}
unsafe extern "system" fn c_callback(
msg_type: c_int,
msg: *const c_char,
user_data: *mut c_void,
) {
let mut user_data = Box::from_raw(user_data as *mut CallbackData);
{
let closure = panic::AssertUnwindSafe(|| {
let message_type = MessageType::from_ffi_type(msg_type).unwrap();
let message = CStr::from_ptr(msg);
(user_data.callback)(message_type, message);
});
if panic::catch_unwind(closure).is_err() {
process::abort();
}
}
mem::forget(user_data);
}
let user_data = Box::new(CallbackData {
callback: Box::new(callback),
});
unsafe {
#[allow(deprecated)]
(self.handle.as_ref().setMessageHandler)(
Some(c_callback),
Box::into_raw(user_data) as *mut c_void,
);
}
}
#[inline]
#[cfg(feature = "gte-vapoursynth-api-36")]
pub fn add_message_handler<F>(self, callback: F) -> MessageHandlerId
where
F: FnMut(MessageType, &CStr) + Send + 'static,
{
struct CallbackData {
callback: Box<dyn FnMut(MessageType, &CStr) + Send + 'static>,
}
unsafe extern "system" fn c_callback(
msg_type: c_int,
msg: *const c_char,
user_data: *mut c_void,
) {
let mut user_data = Box::from_raw(user_data as *mut CallbackData);
{
let closure = panic::AssertUnwindSafe(|| {
let message_type = MessageType::from_ffi_type(msg_type).unwrap();
let message = CStr::from_ptr(msg);
(user_data.callback)(message_type, message);
});
if panic::catch_unwind(closure).is_err() {
process::abort();
}
}
mem::forget(user_data);
}
unsafe extern "system" fn c_free_callback(user_data: *mut c_void) {
let user_data = Box::from_raw(user_data as *mut CallbackData);
drop(user_data);
}
let user_data = Box::new(CallbackData {
callback: Box::new(callback),
});
let id = unsafe {
(self.handle.as_ref().addMessageHandler)(
Some(c_callback),
Some(c_free_callback),
Box::into_raw(user_data) as *mut c_void,
)
};
MessageHandlerId(id)
}
#[inline]
#[cfg_attr(
feature = "gte-vapoursynth-api-36",
deprecated(
note = "use `add_message_handler_trivial` and `remove_message_handler` instead"
)
)]
pub fn set_message_handler_trivial(self, callback: fn(MessageType, &CStr)) {
unsafe extern "system" fn c_callback(
msg_type: c_int,
msg: *const c_char,
user_data: *mut c_void,
) {
let closure = panic::AssertUnwindSafe(|| {
let message_type = MessageType::from_ffi_type(msg_type).unwrap();
let message = CStr::from_ptr(msg);
let callback = *(&user_data as *const _ as *const fn(MessageType, &CStr));
(callback)(message_type, message);
});
if panic::catch_unwind(closure).is_err() {
eprintln!("panic in the set_message_handler_trivial() callback, aborting");
process::abort();
}
}
unsafe {
#[allow(deprecated)]
(self.handle.as_ref().setMessageHandler)(Some(c_callback), callback as *mut c_void);
}
}
#[inline]
#[cfg(feature = "gte-vapoursynth-api-36")]
pub fn add_message_handler_trivial(self, callback: fn(MessageType, &CStr)) -> MessageHandlerId {
unsafe extern "system" fn c_callback(
msg_type: c_int,
msg: *const c_char,
user_data: *mut c_void,
) {
let closure = panic::AssertUnwindSafe(|| {
let message_type = MessageType::from_ffi_type(msg_type).unwrap();
let message = CStr::from_ptr(msg);
let callback = *(&user_data as *const _ as *const fn(MessageType, &CStr));
(callback)(message_type, message);
});
if panic::catch_unwind(closure).is_err() {
eprintln!("panic in the set_message_handler_trivial() callback, aborting");
process::abort();
}
}
let id = unsafe {
(self.handle.as_ref().addMessageHandler)(
Some(c_callback),
None,
callback as *mut c_void,
)
};
MessageHandlerId(id)
}
#[inline]
#[cfg_attr(
feature = "gte-vapoursynth-api-36",
deprecated(note = "use `add_message_handler` and `remove_message_handler` instead")
)]
pub fn clear_message_handler(self) {
unsafe {
#[allow(deprecated)]
(self.handle.as_ref().setMessageHandler)(None, ptr::null_mut());
}
}
#[inline]
#[cfg(feature = "gte-vapoursynth-api-36")]
pub fn remove_message_handler(self, handler_id: MessageHandlerId) {
unsafe {
(self.handle.as_ref().removeMessageHandler)(handler_id.0);
}
}
#[inline]
pub(crate) unsafe fn free_node(self, node: *mut ffi::VSNodeRef) {
(self.handle.as_ref().freeNode)(node);
}
#[inline]
pub(crate) unsafe fn clone_node(self, node: *mut ffi::VSNodeRef) -> *mut ffi::VSNodeRef {
(self.handle.as_ref().cloneNodeRef)(node)
}
#[inline]
pub(crate) unsafe fn get_video_info(
self,
node: *mut ffi::VSNodeRef,
) -> *const ffi::VSVideoInfo {
(self.handle.as_ref().getVideoInfo)(node)
}
#[inline]
pub(crate) unsafe fn get_frame(
self,
n: i32,
node: *mut ffi::VSNodeRef,
err_msg: &mut [c_char],
) -> *const ffi::VSFrameRef {
let len = err_msg.len();
assert!(len <= i32::max_value() as usize);
let len = len as i32;
(self.handle.as_ref().getFrame)(n, node, err_msg.as_mut_ptr(), len)
}
#[inline]
pub(crate) unsafe fn get_frame_async(
self,
n: i32,
node: *mut ffi::VSNodeRef,
callback: ffi::VSFrameDoneCallback,
user_data: *mut c_void,
) {
(self.handle.as_ref().getFrameAsync)(n, node, callback, user_data);
}
#[inline]
pub(crate) unsafe fn free_frame(self, frame: &ffi::VSFrameRef) {
(self.handle.as_ref().freeFrame)(frame);
}
#[inline]
pub(crate) unsafe fn clone_frame(self, frame: &ffi::VSFrameRef) -> *const ffi::VSFrameRef {
(self.handle.as_ref().cloneFrameRef)(frame)
}
#[inline]
pub(crate) unsafe fn get_frame_format(self, frame: &ffi::VSFrameRef) -> *const ffi::VSFormat {
(self.handle.as_ref().getFrameFormat)(frame)
}
#[inline]
pub(crate) unsafe fn get_frame_width(self, frame: &ffi::VSFrameRef, plane: i32) -> i32 {
(self.handle.as_ref().getFrameWidth)(frame, plane)
}
#[inline]
pub(crate) unsafe fn get_frame_height(self, frame: &ffi::VSFrameRef, plane: i32) -> i32 {
(self.handle.as_ref().getFrameHeight)(frame, plane)
}
#[inline]
pub(crate) unsafe fn get_frame_stride(self, frame: &ffi::VSFrameRef, plane: i32) -> i32 {
(self.handle.as_ref().getStride)(frame, plane)
}
#[inline]
pub(crate) unsafe fn get_frame_read_ptr(
self,
frame: &ffi::VSFrameRef,
plane: i32,
) -> *const u8 {
(self.handle.as_ref().getReadPtr)(frame, plane)
}
#[inline]
pub(crate) unsafe fn get_frame_write_ptr(
self,
frame: &mut ffi::VSFrameRef,
plane: i32,
) -> *mut u8 {
(self.handle.as_ref().getWritePtr)(frame, plane)
}
#[inline]
pub(crate) unsafe fn get_frame_props_ro(self, frame: &ffi::VSFrameRef) -> *const ffi::VSMap {
(self.handle.as_ref().getFramePropsRO)(frame)
}
#[inline]
pub(crate) unsafe fn get_frame_props_rw(self, frame: &mut ffi::VSFrameRef) -> *mut ffi::VSMap {
(self.handle.as_ref().getFramePropsRW)(frame)
}
#[inline]
pub(crate) fn create_map(self) -> *mut ffi::VSMap {
unsafe { (self.handle.as_ref().createMap)() }
}
#[inline]
pub(crate) unsafe fn clear_map(self, map: &mut ffi::VSMap) {
(self.handle.as_ref().clearMap)(map);
}
#[inline]
pub(crate) unsafe fn free_map(self, map: &mut ffi::VSMap) {
(self.handle.as_ref().freeMap)(map);
}
#[inline]
pub(crate) unsafe fn get_error(self, map: &ffi::VSMap) -> *const c_char {
(self.handle.as_ref().getError)(map)
}
#[inline]
pub(crate) unsafe fn set_error(self, map: &mut ffi::VSMap, error_message: *const c_char) {
(self.handle.as_ref().setError)(map, error_message)
}
#[inline]
pub(crate) unsafe fn prop_num_keys(self, map: &ffi::VSMap) -> i32 {
(self.handle.as_ref().propNumKeys)(map)
}
#[inline]
pub(crate) unsafe fn prop_get_key(self, map: &ffi::VSMap, index: i32) -> *const c_char {
(self.handle.as_ref().propGetKey)(map, index)
}
#[inline]
pub(crate) unsafe fn prop_delete_key(self, map: &mut ffi::VSMap, key: *const c_char) -> i32 {
(self.handle.as_ref().propDeleteKey)(map, key)
}
#[inline]
pub(crate) unsafe fn prop_num_elements(self, map: &ffi::VSMap, key: *const c_char) -> i32 {
(self.handle.as_ref().propNumElements)(map, key)
}
#[inline]
pub(crate) unsafe fn prop_get_type(self, map: &ffi::VSMap, key: *const c_char) -> c_char {
(self.handle.as_ref().propGetType)(map, key)
}
#[inline]
pub(crate) unsafe fn prop_get_data_size(
self,
map: &ffi::VSMap,
key: *const c_char,
index: i32,
error: &mut i32,
) -> i32 {
(self.handle.as_ref().propGetDataSize)(map, key, index, error)
}
prop_get_something!(prop_get_int, propGetInt, i64);
prop_get_something!(prop_get_float, propGetFloat, f64);
prop_get_something!(prop_get_data, propGetData, *const c_char);
prop_get_something!(prop_get_node, propGetNode, *mut ffi::VSNodeRef);
prop_get_something!(prop_get_frame, propGetFrame, *const ffi::VSFrameRef);
prop_get_something!(prop_get_func, propGetFunc, *mut ffi::VSFuncRef);
prop_set_something!(prop_set_int, propSetInt, i64);
prop_set_something!(prop_set_float, propSetFloat, f64);
prop_set_something!(prop_set_node, propSetNode, *mut ffi::VSNodeRef);
prop_set_something!(prop_set_frame, propSetFrame, *const ffi::VSFrameRef);
prop_set_something!(prop_set_func, propSetFunc, *mut ffi::VSFuncRef);
#[cfg(feature = "gte-vapoursynth-api-31")]
#[inline]
pub(crate) unsafe fn prop_get_int_array(
self,
map: &ffi::VSMap,
key: *const c_char,
error: &mut i32,
) -> *const i64 {
(self.handle.as_ref().propGetIntArray)(map, key, error)
}
#[cfg(feature = "gte-vapoursynth-api-31")]
#[inline]
pub(crate) unsafe fn prop_get_float_array(
self,
map: &ffi::VSMap,
key: *const c_char,
error: &mut i32,
) -> *const f64 {
(self.handle.as_ref().propGetFloatArray)(map, key, error)
}
#[inline]
pub(crate) unsafe fn prop_set_data(
self,
map: &mut ffi::VSMap,
key: *const c_char,
value: &[u8],
append: ffi::VSPropAppendMode,
) -> i32 {
let length = value.len();
assert!(length <= i32::max_value() as usize);
let length = length as i32;
(self.handle.as_ref().propSetData)(map, key, value.as_ptr() as _, length, append as i32)
}
#[cfg(feature = "gte-vapoursynth-api-31")]
#[inline]
pub(crate) unsafe fn prop_set_int_array(
self,
map: &mut ffi::VSMap,
key: *const c_char,
value: &[i64],
) -> i32 {
let length = value.len();
assert!(length <= i32::max_value() as usize);
let length = length as i32;
(self.handle.as_ref().propSetIntArray)(map, key, value.as_ptr(), length)
}
#[cfg(feature = "gte-vapoursynth-api-31")]
#[inline]
pub(crate) unsafe fn prop_set_float_array(
self,
map: &mut ffi::VSMap,
key: *const c_char,
value: &[f64],
) -> i32 {
let length = value.len();
assert!(length <= i32::max_value() as usize);
let length = length as i32;
(self.handle.as_ref().propSetFloatArray)(map, key, value.as_ptr(), length)
}
#[inline]
pub(crate) unsafe fn free_func(self, function: *mut ffi::VSFuncRef) {
(self.handle.as_ref().freeFunc)(function);
}
#[inline]
pub(crate) unsafe fn clone_func(self, function: *mut ffi::VSFuncRef) -> *mut ffi::VSFuncRef {
(self.handle.as_ref().cloneFuncRef)(function)
}
#[inline]
#[cfg(not(feature = "gte-vapoursynth-api-36"))]
pub(crate) unsafe fn get_core_info(self, core: *mut ffi::VSCore) -> *const ffi::VSCoreInfo {
(self.handle.as_ref().getCoreInfo)(core)
}
#[inline]
#[cfg(feature = "gte-vapoursynth-api-36")]
pub(crate) unsafe fn get_core_info(self, core: *mut ffi::VSCore) -> ffi::VSCoreInfo {
use std::mem::MaybeUninit;
let mut core_info = MaybeUninit::uninit();
(self.handle.as_ref().getCoreInfo2)(core, core_info.as_mut_ptr());
core_info.assume_init()
}
#[inline]
pub(crate) unsafe fn get_format_preset(
self,
id: i32,
core: *mut ffi::VSCore,
) -> *const ffi::VSFormat {
(self.handle.as_ref().getFormatPreset)(id, core)
}
#[inline]
pub(crate) unsafe fn register_format(
self,
color_family: ffi::VSColorFamily,
sample_type: ffi::VSSampleType,
bits_per_sample: i32,
sub_sampling_w: i32,
sub_sampling_h: i32,
core: *mut ffi::VSCore,
) -> *const ffi::VSFormat {
(self.handle.as_ref().registerFormat)(
color_family as i32,
sample_type as i32,
bits_per_sample,
sub_sampling_w,
sub_sampling_h,
core,
)
}
#[allow(clippy::too_many_arguments)]
#[inline]
pub(crate) unsafe fn create_filter(
self,
in_: *const ffi::VSMap,
out: *mut ffi::VSMap,
name: *const c_char,
init: ffi::VSFilterInit,
get_frame: ffi::VSFilterGetFrame,
free: ffi::VSFilterFree,
filter_mode: ffi::VSFilterMode,
flags: ffi::VSNodeFlags,
instance_data: *mut c_void,
core: *mut ffi::VSCore,
) {
(self.handle.as_ref().createFilter)(
in_,
out,
name,
init,
get_frame,
free,
filter_mode as _,
flags.0,
instance_data,
core,
);
}
#[inline]
pub(crate) unsafe fn set_video_info(self, vi: &[ffi::VSVideoInfo], node: *mut ffi::VSNode) {
let length = vi.len();
assert!(length <= i32::max_value() as usize);
let length = length as i32;
(self.handle.as_ref().setVideoInfo)(vi.as_ptr(), length, node);
}
#[inline]
pub(crate) unsafe fn set_filter_error(
self,
message: *const c_char,
frame_ctx: *mut ffi::VSFrameContext,
) {
(self.handle.as_ref().setFilterError)(message, frame_ctx);
}
#[inline]
pub(crate) unsafe fn request_frame_filter(
self,
n: i32,
node: *mut ffi::VSNodeRef,
frame_ctx: *mut ffi::VSFrameContext,
) {
(self.handle.as_ref().requestFrameFilter)(n, node, frame_ctx);
}
#[inline]
pub(crate) unsafe fn get_frame_filter(
self,
n: i32,
node: *mut ffi::VSNodeRef,
frame_ctx: *mut ffi::VSFrameContext,
) -> *const ffi::VSFrameRef {
(self.handle.as_ref().getFrameFilter)(n, node, frame_ctx)
}
#[inline]
pub(crate) unsafe fn copy_frame(
self,
f: &ffi::VSFrameRef,
core: *mut ffi::VSCore,
) -> *mut ffi::VSFrameRef {
(self.handle.as_ref().copyFrame)(f, core)
}
#[inline]
pub(crate) unsafe fn new_video_frame(
self,
format: &ffi::VSFormat,
width: i32,
height: i32,
prop_src: *const ffi::VSFrameRef,
core: *mut ffi::VSCore,
) -> *mut ffi::VSFrameRef {
(self.handle.as_ref().newVideoFrame)(format, width, height, prop_src, core)
}
#[inline]
pub(crate) unsafe fn get_plugin_by_id(
self,
identifier: *const c_char,
core: *mut ffi::VSCore,
) -> *mut ffi::VSPlugin {
(self.handle.as_ref().getPluginById)(identifier, core)
}
#[inline]
pub(crate) unsafe fn get_plugin_by_ns(
self,
namespace: *const c_char,
core: *mut ffi::VSCore,
) -> *mut ffi::VSPlugin {
(self.handle.as_ref().getPluginByNs)(namespace, core)
}
#[inline]
pub(crate) unsafe fn get_plugins(self, core: *mut ffi::VSCore) -> *mut ffi::VSMap {
(self.handle.as_ref().getPlugins)(core)
}
#[inline]
pub(crate) unsafe fn get_functions(self, plugin: *mut ffi::VSPlugin) -> *mut ffi::VSMap {
(self.handle.as_ref().getFunctions)(plugin)
}
#[cfg(feature = "gte-vapoursynth-api-31")]
#[inline]
pub(crate) unsafe fn get_plugin_path(self, plugin: *mut ffi::VSPlugin) -> *const c_char {
(self.handle.as_ref().getPluginPath)(plugin)
}
#[inline]
pub(crate) unsafe fn invoke(
self,
plugin: *mut ffi::VSPlugin,
name: *const c_char,
args: *const ffi::VSMap,
) -> *mut ffi::VSMap {
(self.handle.as_ref().invoke)(plugin, name, args)
}
#[inline]
pub(crate) unsafe fn get_output_index(self, frame_ctx: *mut ffi::VSFrameContext) -> i32 {
(self.handle.as_ref().getOutputIndex)(frame_ctx)
}
#[inline]
pub(crate) unsafe fn create_func(
self,
func: ffi::VSPublicFunction,
user_data: *mut c_void,
free: ffi::VSFreeFuncData,
core: *mut ffi::VSCore,
) -> *mut ffi::VSFuncRef {
(self.handle.as_ref().createFunc)(func, user_data, free, core, self.handle.as_ptr())
}
#[inline]
pub(crate) unsafe fn call_func(
self,
func: *mut ffi::VSFuncRef,
in_: *const ffi::VSMap,
out: *mut ffi::VSMap,
) {
(self.handle.as_ref().callFunc)(func, in_, out, ptr::null_mut(), ptr::null());
}
#[inline]
pub(crate) unsafe fn register_function(
self,
name: *const c_char,
args: *const c_char,
args_func: ffi::VSPublicFunction,
function_data: *mut c_void,
plugin: *mut ffi::VSPlugin,
) {
(self.handle.as_ref().registerFunction)(name, args, args_func, function_data, plugin);
}
#[inline]
pub(crate) unsafe fn set_max_cache_size(self, bytes: i64, core: *mut ffi::VSCore) -> i64 {
(self.handle.as_ref().setMaxCacheSize)(bytes, core)
}
#[inline]
pub(crate) unsafe fn set_thread_count(self, threads: c_int, core: *mut ffi::VSCore) -> c_int {
(self.handle.as_ref().setThreadCount)(threads, core)
}
#[inline]
pub fn create_core<'core>(self, threads: i32) -> CoreRef<'core> {
unsafe {
let handle = (self.handle.as_ref().createCore)(threads);
CoreRef::from_ptr(handle)
}
}
}
impl MessageType {
#[inline]
fn ffi_type(self) -> c_int {
let rv = match self {
MessageType::Debug => ffi::VSMessageType::mtDebug,
MessageType::Warning => ffi::VSMessageType::mtWarning,
MessageType::Critical => ffi::VSMessageType::mtCritical,
MessageType::Fatal => ffi::VSMessageType::mtFatal,
};
rv as c_int
}
#[inline]
fn from_ffi_type(x: c_int) -> Option<Self> {
match x {
x if x == ffi::VSMessageType::mtDebug as c_int => Some(MessageType::Debug),
x if x == ffi::VSMessageType::mtWarning as c_int => Some(MessageType::Warning),
x if x == ffi::VSMessageType::mtCritical as c_int => Some(MessageType::Critical),
x if x == ffi::VSMessageType::mtFatal as c_int => Some(MessageType::Fatal),
_ => None,
}
}
}