2012/2/14 Patrick Ohly <[email protected]>:
> On Tue, 2012-02-14 at 16:02 +0100, Patrick Ohly wrote:
>> On Mon, 2012-02-13 at 14:50 +0100, Chris Kühl wrote:
>> > - Krzesimir implemented the missing functionality in the gio-gdbus
>> > wrapper and added code to do blocking calls with minimal extra code
>> > required in consuming classes.
>>
>> In addition to adding a block() method which executes the call, wouldn't
>> it be nicer to also overload the call operator such that if there is no
>> Callback_t parameter, all results are returned directly (special case
>> for a single return value) or as tuple (general case)?
>>
>> The block() call would be more efficient for large return values (avoids
>> one copying), but for small ones the ease of use certainly would be
>> worth it.
>>
>> I've experimented a bit with it and think it can be done.
>>
>> Is there still a need for the block() variant if there was a "normal"
>> blocking call operator()?
>
> Here's a partial implementation. Not all combinations of number of
> parameters and return values are currently spelled out. Is there a
> better approach and would it be worthwhile?
Well, specifiying 44 methods sounds like overkill to me. I do have
some idea, but I don't know if it will work.
Add another template parameter to DBusClientCall:
template <class T, class R>
class DBusClientCall
{
public:
typedef T Callback_t;
typedef R Return_t;
...
};
Add pure virtual method in DBusClientCall:
virtual Return_t demarshal(DBusMessagePtr &msg, DBusConnectionPtr &conn) = 0;
Then example of blocking operator():
Return_t operator () ()
{
// usual body - message creation, preparation, adding parameters...
return sendAndReturn(msg);
}
where sendAndReturn would be:
Return_t sendAndReturn(GDBusMessagePtr &msg)
{
// do synchronous call and throw an exception on error.
GDBusMessagePtr reply(...);
return demarshal(reply, m_conn);
}
DBusClientCall{0,1,2,3} should implement their own demarshal function
and in constructor they should pass return type as a base class second
template parameter:
DBusClientCall2 (const DBusRemoteObject &object, const std::string &method)
: DBusClientCall<Callback_t, boost::tuple<R1, R2> >(object,
method, &DBusClientCall2::dbusCallback)
{
}
This is an idea, so I have no idea if it will work. :) Especially when
Return_t is void.
> diff --git a/src/gdbus/gdbus-cxx-bridge.h b/src/gdbus/gdbus-cxx-bridge.h
> index dc217ca..d56be89 100644
> --- a/src/gdbus/gdbus-cxx-bridge.h
> +++ b/src/gdbus/gdbus-cxx-bridge.h
> @@ -81,6 +81,7 @@ static inline void intrusive_ptr_release(DBusServer
> *server) { dbus_server_unref
> #include <boost/variant.hpp>
> #include <boost/variant/get.hpp>
> #include <boost/utility.hpp>
> +#include <boost/tuple/tuple.hpp>
>
> /* The connection is the only client-exposed type from the C API. To
> * keep changes to a minimum while supporting both dbus
> @@ -3913,6 +3914,20 @@ protected:
>
> typedef T Callback_t;
>
> + /**
> + * Blocking method call: execute call and check for error.
> + * Encoding parameters and decoding return values must be done by
> + * caller.
> + */
> + void doCall(DBusMessagePtr &msg, DBusMessagePtr &reply)
> + {
> + DBusErrorCXX error;
> + reply =
> dbus_connection_send_with_reply_and_block(DBusClientCall<Callback_t>::m_conn.get(),
> msg.get(), -1, &error);
> + if (!reply) {
> + error.throwFailure(DBusClientCall<Callback_t>::m_method);
> + }
> + }
> +
> void prepare(DBusMessagePtr &msg)
> {
> // Constructor steals reference, reset() doesn't!
> @@ -4225,6 +4240,20 @@ public:
> : DBusClientCall<Callback_t>(object, method,
> &DBusClientCall0::dbusCallback)
> {
> }
> +
> + // keep call operator from base class visible
> + using DBusClientCall<Callback_t>::operator ();
> +
> + // return once the call is done, throws runtime_error if it fails
> + template <class A1>
> + void operator () (const A1 &a1)
> + {
> + DBusMessagePtr msg;
> + prepare(msg);
> + AppendRetvals(msg) << a1;
> + DBusMessagePtr reply;
> + DBusClientCall<Callback_t>::doCall(msg, reply);
> + }
> };
>
> /** 1 return value and 0 or more parameters */
> @@ -4257,6 +4286,24 @@ public:
> : DBusClientCall<Callback_t>(object, method,
> &DBusClientCall1::dbusCallback)
> {
> }
> +
> + using DBusClientCall<Callback_t>::operator ();
> +
> + template <class A1>
> + R1 operator () (const A1 &a1)
> + {
> + DBusMessagePtr msg;
> + DBusClientCall<Callback_t>::prepare(msg);
> + AppendRetvals(msg) << a1;
> + DBusErrorCXX error;
> + DBusMessagePtr reply =
> dbus_connection_send_with_reply_and_block(DBusClientCall<Callback_t>::m_conn.get(),
> msg.get(), -1, &error);
> + if (!reply) {
> + error.throwFailure(DBusClientCall<Callback_t>::m_method);
> + }
> + typename dbus_traits<R1>::host_type r;
> + ExtractArgs(DBusClientCall<Callback_t>::m_conn.get(),
> reply.get()) >> Get<R1>(r);
> + return r;
> + }
> };
>
> /** 2 return value and 0 or more parameters */
> @@ -4291,6 +4338,34 @@ public:
> : DBusClientCall<Callback_t>(object, method,
> &DBusClientCall2::dbusCallback)
> {
> }
> +
> + using DBusClientCall<Callback_t>::operator ();
> +
> + boost::tuple<R1, R2> operator () ()
> + {
> + DBusMessagePtr msg;
> + DBusClientCall<Callback_t>::prepare(msg);
> + DBusMessagePtr reply;
> + DBusClientCall<Callback_t>::doCall(msg, reply);
> + boost::tuple<R1, R2> r;
> + boost::get<0>(r);
> + ExtractArgs(DBusClientCall<Callback_t>::m_conn.get(),
> reply.get()) >> Get<R1>(boost::get<0>(r)) >> Get<R2>(boost::get<1>(r));
> + return r;
> + }
> +
> + template <class A1>
> + boost::tuple<R1, R2> operator () (const A1 &a1)
> + {
> + DBusMessagePtr msg;
> + DBusClientCall<Callback_t>::prepare(msg);
> + AppendRetvals(msg) << a1;
> + DBusMessagePtr reply;
> + DBusClientCall<Callback_t>::doCall(msg, reply);
> + boost::tuple<R1, R2> r;
> + ExtractArgs(DBusClientCall<Callback_t>::m_conn.get(),
> reply.get()) >> Get<R1>(r[0]) >> Get<R2>(r[1]);
> + return r;
> + }
> +
> };
>
> /** 3 return value and 0 or more parameters */
>
> --
> Best Regards, Patrick Ohly
>
> The content of this message is my personal opinion only and although
> I am an employee of Intel, the statements I make here in no way
> represent Intel's position on the issue, nor am I authorized to speak
> on behalf of Intel on this matter.
>
>
_______________________________________________
SyncEvolution mailing list
[email protected]
http://lists.syncevolution.org/listinfo/syncevolution