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

Reply via email to