use std::{
ffi::{CStr, CString},
os::raw::{c_char, c_void},
ptr,
};
use libcogcore_sys as sys;
use crate::error::GlibError;
pub(crate) fn optional_cstring(value: Option<&str>) -> crate::Result<Option<CString>> {
value.map(CString::new).transpose().map_err(Into::into)
}
pub(crate) fn cstring(value: &str) -> crate::Result<CString> {
CString::new(value).map_err(Into::into)
}
pub(crate) fn optional_ptr(value: Option<&CString>) -> *const c_char {
value.map_or(ptr::null(), |value| value.as_ptr())
}
pub(crate) fn bool_to_gboolean(value: bool) -> sys::gboolean {
if value { 1 } else { 0 }
}
pub(crate) fn gboolean_to_bool(value: sys::gboolean) -> bool {
value != 0
}
pub(crate) fn string_from_const(ptr: *const c_char) -> Option<String> {
if ptr.is_null() {
return None;
}
let value = unsafe { CStr::from_ptr(ptr) };
Some(value.to_string_lossy().into_owned())
}
pub(crate) fn string_from_owned(ptr: *mut c_char, context: &'static str) -> crate::Result<String> {
if ptr.is_null() {
return Err(crate::Error::Null(context));
}
let value = unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
let mem = ptr.cast::<c_void>();
unsafe { sys::g_free(mem) };
Ok(value)
}
pub(crate) fn take_gerror(ptr: *mut sys::GError) -> GlibError {
if ptr.is_null() {
return GlibError {
domain: 0,
code: 0,
message: "unknown GLib error".to_string(),
};
}
let error = unsafe { &*ptr };
let message = string_from_const(error.message).unwrap_or_else(|| "unknown GLib error".into());
let glib_error = GlibError {
domain: error.domain,
code: error.code,
message,
};
unsafe { sys::g_error_free(ptr) };
glib_error
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rejects_embedded_nul() {
assert!(cstring("bad\0input").is_err());
}
#[test]
fn converts_gboolean() {
assert_eq!(bool_to_gboolean(false), 0);
assert_eq!(bool_to_gboolean(true), 1);
assert!(!gboolean_to_bool(0));
assert!(gboolean_to_bool(27));
}
}