Merge pull request #18 from trishume/ddbus/enhancement/exceptions

Error handling improvements
This commit is contained in:
Tristan Hume 2017-07-10 10:53:17 -07:00 committed by GitHub
commit 547705ae11
4 changed files with 82 additions and 25 deletions

View file

@ -11,7 +11,7 @@ It currently supports:
- Calling methods - Calling methods
- Creating wrapper objects for DBus interfaces - Creating wrapper objects for DBus interfaces
- Seamlessly converting too and from D types - Seamlessly converting to and from D types
- Handling method calls and signals (includes introspection support) - Handling method calls and signals (includes introspection support)
# Installation # Installation
@ -130,6 +130,7 @@ msg.readTuple!(typeof(args))().assertEqual(args);
- `simple`: simpler wrappers around other functionality. - `simple`: simpler wrappers around other functionality.
- `conv`: low level type marshaling methods. - `conv`: low level type marshaling methods.
- `util`: templates for working with D type marshaling like `canDBus!T`. - `util`: templates for working with D type marshaling like `canDBus!T`.
- `exception`: exception classes
- `c_lib`: a D translation of the DBus C headers. - `c_lib`: a D translation of the DBus C headers.
Importing `ddbus` publicly imports the `thin`,`router`,`bus` and `simple` modules. Importing `ddbus` publicly imports the `thin`,`router`,`bus` and `simple` modules.
@ -169,7 +170,7 @@ It would be better to watch a file descriptor asynchronously in the event loop i
`ddbus` should be complete for everyday use but is missing some fanciness that it easily could and should have: `ddbus` should be complete for everyday use but is missing some fanciness that it easily could and should have:
- Support for adding file descriptors to event loops like vibe.d so that it only wakes up when messages arrive and not on a timer. - Support for adding file descriptors to event loops like vibe.d so that it only wakes up when messages arrive and not on a timer.
- Marshaling of DBus path and file descriptor objects - Marshaling of file descriptor objects
- Better efficiency in some places, particularly the object wrapping allocates tons of delegates for every method. - Better efficiency in some places, particularly the object wrapping allocates tons of delegates for every method.
Pull requests are welcome, the codebase is pretty small and other than the template metaprogramming for type marshaling is fairly straightforward. Pull requests are welcome, the codebase is pretty small and other than the template metaprogramming for type marshaling is fairly straightforward.

View file

@ -1,8 +1,10 @@
module ddbus.conv; module ddbus.conv;
import ddbus.c_lib; import ddbus.c_lib;
import ddbus.exception : TypeMismatchException;
import ddbus.util; import ddbus.util;
import ddbus.thin; import ddbus.thin;
import std.exception : enforce;
import std.string; import std.string;
import std.typecons; import std.typecons;
import std.range; import std.range;
@ -134,12 +136,10 @@ T readIter(T)(DBusMessageIter *iter) if (canDBus!T) {
return ret; return ret;
} }
} }
static if(isTuple!T) { static if(!is(T == DBusAny) && !is(T == Variant!DBusAny)) {
assert(dbus_message_iter_get_arg_type(iter) == 'r'); auto argType = dbus_message_iter_get_arg_type(iter);
} else static if(is(T == DictionaryEntry!(K1, V1), K1, V1)) { enforce(argType == typeCode!T(),
assert(dbus_message_iter_get_arg_type(iter) == 'e'); new TypeMismatchException(argType, typeCode!T()));
} else static if(!is(T == DBusAny) && !is(T == Variant!DBusAny)) {
assert(dbus_message_iter_get_arg_type(iter) == typeCode!T());
} }
static if(is(T==string) || is(T==ObjectPath)) { static if(is(T==string) || is(T==ObjectPath)) {
const(char)* cStr; const(char)* cStr;
@ -272,6 +272,11 @@ unittest {
auto args = tuple(5,true,"wow",var(5.9),[6,5],tuple(6.2,4,[["lol"]],emptyB,var([4,2])),map,anyVar,complexVar); auto args = tuple(5,true,"wow",var(5.9),[6,5],tuple(6.2,4,[["lol"]],emptyB,var([4,2])),map,anyVar,complexVar);
msg.build(args.expand); msg.build(args.expand);
msg.signature().assertEqual("ibsvai(diaasabv)a{ss}tv"); msg.signature().assertEqual("ibsvai(diaasabv)a{ss}tv");
msg.read!string().assertThrow!TypeMismatchException();
msg.readTuple!(Tuple!(int, bool, double)).assertThrow!TypeMismatchException();
msg.readTuple!(Tuple!(int, bool, string, double)).assertEqual(tuple(5,true,"wow", 5.9));
msg.readTuple!(typeof(args))().assertEqual(args); msg.readTuple!(typeof(args))().assertEqual(args);
DBusMessageIter iter; DBusMessageIter iter;
dbus_message_iter_init(msg.msg, &iter); dbus_message_iter_init(msg.msg, &iter);

66
source/ddbus/exception.d Normal file
View file

@ -0,0 +1,66 @@
module ddbus.exception;
import ddbus.c_lib;
package T wrapErrors(T)(
T delegate(DBusError *err) del,
string file = __FILE__,
size_t line = __LINE__,
Throwable next = null
) {
DBusError error;
dbus_error_init(&error);
T ret = del(&error);
if(dbus_error_is_set(&error)) {
auto ex = new DBusException(&error, file, line, next);
dbus_error_free(&error);
throw ex;
}
return ret;
}
/++
Thrown when a DBus error code was returned by libdbus.
+/
class DBusException : Exception {
private this(
scope DBusError *err,
string file = __FILE__,
size_t line = __LINE__,
Throwable next = null
) pure nothrow {
import std.string : fromStringz;
super(err.message.fromStringz().idup, file, line, next);
}
}
/++
Thrown when the signature of a message does not match the requested types.
+/
class TypeMismatchException : Exception {
package this(
int expectedType,
int actualType,
string file = __FILE__,
size_t line = __LINE__,
Throwable next = null
) pure nothrow @safe {
_expectedType = expectedType;
_actualType = actualType;
super("The type of value at the current position in the message does not match the type of value to be read."
~ " Expected: " ~ cast(char) expectedType ~ ", Got: " ~ cast(char) actualType);
}
int expectedType() @property pure const nothrow @nogc {
return _expectedType;
}
int actualType() @property pure const nothrow @nogc {
return _actualType;
}
private:
int _expectedType;
int _actualType;
}

View file

@ -12,23 +12,8 @@ import std.conv;
import std.range; import std.range;
import std.algorithm; import std.algorithm;
class DBusException : Exception { // This import is public for backwards compatibility
this(DBusError *err) { public import ddbus.exception : wrapErrors, DBusException;
super(err.message.fromStringz().idup);
}
}
T wrapErrors(T)(T delegate(DBusError *err) del) {
DBusError error;
dbus_error_init(&error);
T ret = del(&error);
if(dbus_error_is_set(&error)) {
auto ex = new DBusException(&error);
dbus_error_free(&error);
throw ex;
}
return ret;
}
struct ObjectPath { struct ObjectPath {
private string _value; private string _value;