Skip to content
This repository has been archived by the owner on Jun 8, 2021. It is now read-only.

BoolError: allow owning the message #419

Merged
merged 1 commit into from
Jan 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 115 additions & 5 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use std::ffi::CStr;
use Quark;
use std::borrow::Cow;
use std::error;
use std::fmt;
use std::str;
Expand Down Expand Up @@ -132,26 +133,135 @@ pub trait ErrorDomain: Copy {
}

/// Generic error used for functions that fail without any further information
#[macro_export]
macro_rules! glib_bool_error(
// Plain strings
($msg:expr) => {
$crate::BoolError::new($msg, file!(), module_path!(), line!())
};

// Format strings
($($msg:tt)*) => { {
$crate::BoolError::new(format!($($msg)*), file!(), module_path!(), line!())
}};
);

#[macro_export]
macro_rules! glib_result_from_gboolean(
// Plain strings
($ffi_bool:expr, $msg:expr) => {
$crate::BoolError::from_glib($ffi_bool, $msg, file!(), module_path!(), line!())
};

// Format strings
($ffi_bool:expr, $($msg:tt)*) => { {
$crate::BoolError::from_glib(
$ffi_bool,
format!($($msg)*),
file!(),
module_path!(),
line!(),
)
}};
);

#[derive(Debug)]
pub struct BoolError(pub &'static str);
pub struct BoolError {
pub message: Cow<'static, str>,
#[doc(hidden)]
pub filename: &'static str,
#[doc(hidden)]
pub function: &'static str,
#[doc(hidden)]
pub line: u32,
}

impl BoolError {
pub fn from_glib(b: glib_ffi::gboolean, s: &'static str) -> Result<(), Self> {
pub fn new<Msg: Into<Cow<'static, str>>>(
message: Msg,
filename: &'static str,
function: &'static str,
line: u32,
) -> Self {
BoolError {
message: message.into(),
filename,
function,
line,
}
}

pub fn from_glib<Msg: Into<Cow<'static, str>>>(
b: glib_ffi::gboolean,
message: Msg,
filename: &'static str,
function: &'static str,
line: u32,
) -> Result<(), Self> {
match b {
glib_ffi::GFALSE => Err(BoolError(s)),
glib_ffi::GFALSE => Err(BoolError::new(
message,
filename,
function,
line,
)),
_ => Ok(()),
}
}
}

impl fmt::Display for BoolError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
write!(
f,
"Error {:?} in {:?} at {}:{}",
self.message, self.function, self.filename, self.line
)
}
}

impl error::Error for BoolError {
fn description(&self) -> &str {
self.0
self.message.as_ref()
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_bool_error() {
use std::error::Error;

let from_static_msg = glib_bool_error!("Static message");
assert_eq!(from_static_msg.description(), "Static message");

let from_dynamic_msg = glib_bool_error!("{} message", "Dynamic");
assert_eq!(from_dynamic_msg.description(), "Dynamic message");

let false_static_res = glib_result_from_gboolean!(glib_ffi::GFALSE, "Static message");
assert!(false_static_res.is_err());
let static_err = false_static_res.err().unwrap();
assert_eq!(static_err.description(), "Static message");

let true_static_res = glib_result_from_gboolean!(glib_ffi::GTRUE, "Static message");
assert!(true_static_res.is_ok());

let false_dynamic_res = glib_result_from_gboolean!(
glib_ffi::GFALSE,
"{} message",
"Dynamic"
);
assert!(false_dynamic_res.is_err());
let dynamic_err = false_dynamic_res.err().unwrap();
assert_eq!(dynamic_err.description(), "Dynamic message");

let true_dynamic_res = glib_result_from_gboolean!(
glib_ffi::GTRUE,
"{} message",
"Dynamic"
);
assert!(true_dynamic_res.is_ok());
}
}
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ pub mod boxed;
#[macro_use]
pub mod shared;
#[macro_use]
pub mod error;
#[macro_use]
pub mod object;

pub use auto::*;
Expand All @@ -174,7 +176,6 @@ pub mod char;
pub use char::*;
mod checksum;
pub mod closure;
pub mod error;
mod enums;
mod file_error;
mod key_file;
Expand Down
38 changes: 20 additions & 18 deletions src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ impl Object {
use std::ffi::CString;

if !type_.is_a(&Object::static_type()) {
return Err(BoolError("Can't instantiate non-GObject objects"));
return Err(glib_bool_error!("Can't instantiate non-GObject objects"));
}

let params = properties.iter()
Expand All @@ -819,7 +819,7 @@ impl Object {
unsafe {
let ptr = gobject_ffi::g_object_newv(type_.to_glib(), params_c.len() as u32, mut_override(params_c.as_ptr()));
if ptr.is_null() {
Err(BoolError("Can't instantiate object"))
Err(glib_bool_error!("Can't instantiate object"))
} else if gobject_ffi::g_object_is_floating(ptr) != glib_ffi::GFALSE {
Ok(from_glib_none(ptr))
} else {
Expand Down Expand Up @@ -880,12 +880,12 @@ impl<T: IsA<Object>> ObjectExt for T {
let pspec = match self.find_property(property_name) {
Some(pspec) => pspec,
None => {
return Err(BoolError("property not found"));
return Err(glib_bool_error!("property not found"));
}
};

if !pspec.get_flags().contains(::ParamFlags::WRITABLE) || pspec.get_flags().contains(::ParamFlags::CONSTRUCT_ONLY) {
return Err(BoolError("property is not writable"));
return Err(glib_bool_error!("property is not writable"));
}

unsafe {
Expand All @@ -897,14 +897,16 @@ impl<T: IsA<Object>> ObjectExt for T {
mut_override(property_value.to_glib_none().0),
pspec.get_value_type().to_glib()));
if !valid_type {
return Err(BoolError("property can't be set from the given type"));
return Err(glib_bool_error!("property can't be set from the given type"));
}

let changed: bool = from_glib(gobject_ffi::g_param_value_validate(
pspec.to_glib_none().0, mut_override(property_value.to_glib_none().0)));
let change_allowed = pspec.get_flags().contains(::ParamFlags::LAX_VALIDATION);
if changed && !change_allowed {
return Err(BoolError("property can't be set from given value, it is invalid or out of range"));
return Err(glib_bool_error!(
"property can't be set from given value, it is invalid or out of range"
));
}

gobject_ffi::g_object_set_property(self.to_glib_none().0,
Expand All @@ -921,12 +923,12 @@ impl<T: IsA<Object>> ObjectExt for T {
let pspec = match self.find_property(property_name) {
Some(pspec) => pspec,
None => {
return Err(BoolError("property not found"));
return Err(glib_bool_error!("property not found"));
}
};

if !pspec.get_flags().contains(::ParamFlags::READABLE) {
return Err(BoolError("property is not readable"));
return Err(glib_bool_error!("property is not readable"));
}

unsafe {
Expand All @@ -935,7 +937,7 @@ impl<T: IsA<Object>> ObjectExt for T {

// This can't really happen unless something goes wrong inside GObject
if value.type_() == ::Type::Invalid {
Err(BoolError("Failed to get property value"))
Err(glib_bool_error!("Failed to get property value"))
} else {
Ok(value)
}
Expand Down Expand Up @@ -1034,13 +1036,13 @@ impl<T: IsA<Object>> ObjectExt for T {
&mut signal_detail, true.to_glib()));

if !found {
return Err(BoolError("Signal not found"));
return Err(glib_bool_error!("Signal not found"));
}

let mut details = mem::zeroed();
gobject_ffi::g_signal_query(signal_id, &mut details);
if details.signal_id != signal_id {
return Err(BoolError("Signal not found"));
return Err(glib_bool_error!("Signal not found"));
}

// This is actually G_SIGNAL_TYPE_STATIC_SCOPE
Expand Down Expand Up @@ -1075,7 +1077,7 @@ impl<T: IsA<Object>> ObjectExt for T {
closure.to_glib_none().0, after.to_glib());

if handler == 0 {
Err(BoolError("Failed to connect to signal"))
Err(glib_bool_error!("Failed to connect to signal"))
} else {
Ok(from_glib(handler))
}
Expand All @@ -1095,23 +1097,23 @@ impl<T: IsA<Object>> ObjectExt for T {
&mut signal_detail, true.to_glib()));

if !found {
return Err(BoolError("Signal not found"));
return Err(glib_bool_error!("Signal not found"));
}

let mut details = mem::zeroed();
gobject_ffi::g_signal_query(signal_id, &mut details);
if details.signal_id != signal_id {
return Err(BoolError("Signal not found"));
return Err(glib_bool_error!("Signal not found"));
}

if details.n_params != args.len() as u32 {
return Err(BoolError("Incompatible number of arguments"));
return Err(glib_bool_error!("Incompatible number of arguments"));
}

for i in 0..(details.n_params as usize) {
let arg_type = *(details.param_types.add(i)) & (!gobject_ffi::G_TYPE_FLAG_RESERVED_ID_BIT);
if arg_type != args[i].to_value_type().to_glib() {
return Err(BoolError("Incompatible argument types"));
return Err(glib_bool_error!("Incompatible argument types"));
}
}

Expand Down Expand Up @@ -1191,13 +1193,13 @@ impl ObjectClass {
let ptype = self.get_property_type(property_name);

match (ptype, type_) {
(None, _) => Err(BoolError("Invalid property name")),
(None, _) => Err(glib_bool_error!("Invalid property name")),
(Some(_), None) => Ok(()),
(Some(ptype), Some(type_)) => {
if ptype == type_ {
Ok(())
} else {
Err(BoolError("Invalid property type"))
Err(glib_bool_error!("Invalid property type"))
}
},
}
Expand Down
12 changes: 8 additions & 4 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ pub fn setenv<K: AsRef<OsStr>, V: AsRef<OsStr>>(variable_name: K, value: V, over
use ffi::g_setenv;

unsafe {
BoolError::from_glib(g_setenv(variable_name.as_ref().to_glib_none().0,
value.as_ref().to_glib_none().0,
overwrite.to_glib()),
"Failed to set environment variable")
glib_result_from_gboolean!(
g_setenv(
variable_name.as_ref().to_glib_none().0,
value.as_ref().to_glib_none().0,
overwrite.to_glib(),
),
"Failed to set environment variable"
)
}
}

Expand Down