1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Callback.h
12 #ifndef ZYPP_CALLBACK_H
13 #define ZYPP_CALLBACK_H
15 #include "zypp/base/NonCopyable.h"
16 #include "zypp/UserData.h"
18 ///////////////////////////////////////////////////////////////////
20 { /////////////////////////////////////////////////////////////////
22 /** \todo Eliminate this! */
29 ///////////////////////////////////////////////////////////////////
32 * \par The task report structure (SENDER SIDE).
34 * A default constructible struct derived from callback::ReportBase.
35 * It \b must \b not conatin any data, just virtual methods.
37 * These are the functions the sender invokes, and which will be forwarded
38 * to some receiver. If no receiver is present, the defined default
39 * implementations are invoked.
41 * For methods returning non-void, define a reasonable return value,
42 * because this is what you get back in case no receiver is listening.
44 * That way the sending side does not need to know whether some receiver
45 * is listening. And it enables the receiver to return a reasonable value,
46 * in case he's got no idea, what else to return.
49 * struct Foo : public callback::ReportBase
51 * virtual void ping( int i )
59 * \par Sending a Task report (SENDER SIDE).
61 * Simply create a callback::SendReport<_Report>, where _Report
62 * is your task report structure. Invoke the callback functions
63 * as needed. That's it.
65 * \note Even creation and destruction of a callback::SendReport
66 * are indicated to a receiver. So even in case of an Exception,
67 * the receiver is able to recognize, that the task ended.
68 * So don't create it without need.
72 * callback::SendReport<Foo> report;
74 * int response = report->pong();
78 * \par Receiving Task reports (RECEIVER SIDE).
80 * To receive task reports of type \c Foo the recipient class
81 * derives from callback::ReceiveReport\<Foo\>. callback::ReceiveReport
82 * inherits \c Foo and provides two additional virtual methods:
85 * virtual void reportbegin() {}
86 * virtual void reportend() {}
89 * These two are automatically invoked, whenever the sender
90 * creates a callback::SendReport instance, and when it gets
91 * destructed. So even if the sending task is aborted without
92 * sending an explicit notification, the reciever may notice it,
93 * by overloading \c reportend.
95 * Overload the methods you're interested in.
97 * \note In case you must return some value and don't know which,
98 * return the task structures default. The author of the task
99 * structure had to provide this value, so it's probabely better
100 * than anything you \e invent.
104 * ...// don't know what to return?
105 * return Foo::somefunction();
109 * \par Connecting the Receiver
111 * For this callback::ReceiveReport provides 4 methods:
115 * bool connected() const;
116 * ReceiveReport * whoIsConnected() const;
119 * \li \c connect Connect this ReceiveReport (in case some other
120 * ReceiveReport is connected, it get disconnected. Remember its
122 * \li \c disconnect Disconnect this ReceiveReport in case it is
123 * connected. If not connected nothing happens.
124 * \li \c connected Test whether this ReceiveReport is currently
126 * \li \c whoIsConnected Return a 'ReceiveReport*' to the currently
127 * connected ReceiveReport, or \c NULL if none is connected.
129 * \par Passing Userdata via Callbacks
131 * For typesafe passing of user data via callbacks \see \ref UserData.
135 { /////////////////////////////////////////////////////////////////
140 typedef callback::UserData UserData;
141 virtual ~ReportBase()
146 template<class _Report>
147 class DistributeReport;
150 template<class _Report>
151 struct ReceiveReport : public _Report
153 typedef _Report ReportType;
154 typedef typename ReportType::UserData UserData;
155 typedef ReceiveReport<_Report> Receiver;
156 typedef DistributeReport<_Report> Distributor;
158 virtual ~ReceiveReport()
161 ReceiveReport * whoIsConnected() const
162 { return Distributor::instance().getReceiver(); }
164 bool connected() const
165 { return whoIsConnected() == this; }
168 { Distributor::instance().setReceiver( *this ); }
171 { Distributor::instance().unsetReceiver( *this ); }
173 virtual void reportbegin()
175 virtual void reportend()
180 template<class _Report>
181 struct DistributeReport
184 typedef _Report ReportType;
185 typedef typename ReportType::UserData UserData;
186 typedef ReceiveReport<_Report> Receiver;
187 typedef DistributeReport<_Report> Distributor;
189 static DistributeReport & instance()
191 static DistributeReport _self;
195 Receiver * getReceiver() const
196 { return _receiver == &_noReceiver ? 0 : _receiver; }
198 void setReceiver( Receiver & rec_r )
199 { _receiver = &rec_r; }
201 void unsetReceiver( Receiver & rec_r )
202 { if ( _receiver == &rec_r ) noReceiver(); }
205 { _receiver = &_noReceiver; }
208 Receiver * operator->()
209 { return _receiver; }
213 : _receiver( &_noReceiver )
215 Receiver _noReceiver;
216 Receiver * _receiver;
220 template<class _Report>
221 struct SendReport : private zypp::base::NonCopyable
223 typedef _Report ReportType;
224 typedef typename ReportType::UserData UserData;
225 typedef ReceiveReport<_Report> Receiver;
226 typedef DistributeReport<_Report> Distributor;
229 { Distributor::instance()->reportbegin(); }
232 { Distributor::instance()->reportend(); }
234 static Receiver * whoIsConnected()
235 { return Distributor::instance().getReceiver(); }
237 static bool connected()
238 { return whoIsConnected(); }
240 Distributor & operator->()
241 { return Distributor::instance(); }
244 /** Temporarily connect a ReceiveReport then restore the previous one.
246 * Pass the ReceiveReport you want to connect temporarily
247 * to the ctor. The ReceiveReport is connected, a previously
248 * connected ReceiveReport is remembered and re-connected in
250 * Use the default ctpr to temporarily disconnect any connected report.
252 * struct FooReceive : public callback::ReceiveReport<Foo>
254 * struct FooReceive2 : public callback::ReceiveReport<Foo>
261 * ... // r receiving the report
263 * callback::TempConnect<Foo> temp( r2 );
264 * ...// r2 receiving the report
266 * ...// r receiving the report
269 template<class _Report>
272 typedef _Report ReportType;
273 typedef typename ReportType::UserData UserData;
274 typedef ReceiveReport<_Report> Receiver;
275 typedef DistributeReport<_Report> Distributor;
278 : _oldRec( Distributor::instance().getReceiver() )
280 Distributor::instance().noReceiver();
283 TempConnect( Receiver & rec_r )
284 : _oldRec( Distributor::instance().getReceiver() )
292 Distributor::instance().setReceiver( *_oldRec );
294 Distributor::instance().noReceiver();
300 /////////////////////////////////////////////////////////////////
301 } // namespace callback
302 ///////////////////////////////////////////////////////////////////
303 /////////////////////////////////////////////////////////////////
305 ///////////////////////////////////////////////////////////////////
306 #endif // ZYPP_CALLBACK_H