1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Callback.h
12 #ifndef ZYPP_CALLBACK_H
13 #define ZYPP_CALLBACK_H
15 #include "zypp/base/NonCopyable.h"
17 ///////////////////////////////////////////////////////////////////
19 { /////////////////////////////////////////////////////////////////
21 /** \todo Eliminate this! */
28 ///////////////////////////////////////////////////////////////////
31 * \par The task report structure (SENDER SIDE).
33 * A default constructible struct derived from callback::ReportBase.
34 * It \b must \b not conatin any data, just virtual methods.
36 * These are the functions the sender invokes, and which will be forwarded
37 * to some receiver. If no receiver is present, the defined default
38 * implementations are invoked.
40 * For methods returning non-void, define a reasonable return value,
41 * because this is what you get back in case no receiver is listening.
43 * That way the sending side does not need to know whether some receiver
44 * is listening. And it enables the receiver to return a reasonable value,
45 * in case he's got no idea, what else to return.
48 * struct Foo : public callback::ReportBase
50 * virtual void ping( int i )
58 * \par Sending a Task report (SENDER SIDE).
60 * Simply create a callback::SendReport<_Report>, where _Report
61 * is your task report structure. Invoke the callback functions
62 * as needed. That's it.
64 * \note Even creation and destruction of a callback::SendReport
65 * are indicated to a receiver. So even in case of an Exception,
66 * the receiver is able to recognize, that the task ended.
67 * So don't create it without need.
71 * callback::SendReport<Foo> report;
73 * int response = report->pong();
77 * \par Receiving Task reports (RECEIVER SIDE).
79 * To receive task reports of type \c Foo the recipient class
80 * derives from callback::ReceiveReport\<Foo\>. callback::ReceiveReport
81 * inherits \c Foo and provides two additional virtual methods:
84 * virtual void reportbegin() {}
85 * virtual void reportend() {}
88 * These two are automatically invoked, whenever the sender
89 * creates a callback::SendReport instance, and when it gets
90 * destructed. So even if the sending task is aborted without
91 * sending an explicit notification, the reciever may notice it,
92 * by overloading \c reportend.
94 * Overload the methods you're interested in.
96 * \note In case you must return some value and don't know which,
97 * return the task structures default. The author of the task
98 * structure had to provide this value, so it's probabely better
99 * than anything you \e invent.
103 * ...// don't know what to return?
104 * return Foo::somefunction();
108 * \par Connecting the Receiver
110 * For this callback::ReceiveReport provides 4 methods:
114 * bool connected() const;
115 * ReceiveReport * whoIsConnected() const;
118 * \li \c connect Connect this ReceiveReport (in case some other
119 * ReceiveReport is connected, it get disconnected. Remember its
121 * \li \c disconnect Disconnect this ReceiveReport in case it is
122 * connected. If not connected nothing happens.
123 * \li \c connected Test whether this ReceiveReport is currently
125 * \li \c whoIsConnected Return a 'ReceiveReport*' to the currently
126 * connected ReceiveReport, or \c NULL if none is connected.
128 * \par Passing Userdata via Callbacks
130 * For typesafe passing of user data via callbacks \see \ref UserData.
134 { /////////////////////////////////////////////////////////////////
139 virtual ~ReportBase()
144 template<class _Report>
145 class DistributeReport;
148 template<class _Report>
149 struct ReceiveReport : public _Report
151 typedef _Report ReportType;
152 typedef ReceiveReport<_Report> Receiver;
153 typedef DistributeReport<_Report> Distributor;
155 virtual ~ReceiveReport()
158 ReceiveReport * whoIsConnected() const
159 { return Distributor::instance().getReceiver(); }
161 bool connected() const
162 { return whoIsConnected() == this; }
165 { Distributor::instance().setReceiver( *this ); }
168 { Distributor::instance().unsetReceiver( *this ); }
170 virtual void reportbegin()
172 virtual void reportend()
177 template<class _Report>
178 struct DistributeReport
181 typedef _Report ReportType;
182 typedef ReceiveReport<_Report> Receiver;
183 typedef DistributeReport<_Report> Distributor;
185 static DistributeReport & instance()
187 static DistributeReport _self;
191 Receiver * getReceiver() const
192 { return _receiver == &_noReceiver ? 0 : _receiver; }
194 void setReceiver( Receiver & rec_r )
195 { _receiver = &rec_r; }
197 void unsetReceiver( Receiver & rec_r )
198 { if ( _receiver == &rec_r ) noReceiver(); }
201 { _receiver = &_noReceiver; }
204 Receiver * operator->()
205 { return _receiver; }
209 : _receiver( &_noReceiver )
211 Receiver _noReceiver;
212 Receiver * _receiver;
216 template<class _Report>
217 struct SendReport : private zypp::base::NonCopyable
219 typedef _Report ReportType;
220 typedef ReceiveReport<_Report> Receiver;
221 typedef DistributeReport<_Report> Distributor;
224 { Distributor::instance()->reportbegin(); }
227 { Distributor::instance()->reportend(); }
229 static Receiver * whoIsConnected()
230 { return Distributor::instance().getReceiver(); }
232 static bool connected()
233 { return whoIsConnected(); }
235 Distributor & operator->()
236 { return Distributor::instance(); }
239 /** Temporarily connect a ReceiveReport then restore the previous one.
241 * Pass the ReceiveReport you want to connect temporarily
242 * to the ctor. The ReceiveReport is connected, a previously
243 * connected ReceiveReport is remembered and re-connected in
245 * Use the default ctpr to temporarily disconnect any connected report.
247 * struct FooReceive : public callback::ReceiveReport<Foo>
249 * struct FooReceive2 : public callback::ReceiveReport<Foo>
256 * ... // r receiving the report
258 * callback::TempConnect<Foo> temp( r2 );
259 * ...// r2 receiving the report
261 * ...// r receiving the report
264 template<class _Report>
267 typedef _Report ReportType;
268 typedef ReceiveReport<_Report> Receiver;
269 typedef DistributeReport<_Report> Distributor;
272 : _oldRec( Distributor::instance().getReceiver() )
274 Distributor::instance().noReceiver();
277 TempConnect( Receiver & rec_r )
278 : _oldRec( Distributor::instance().getReceiver() )
286 Distributor::instance().setReceiver( *_oldRec );
288 Distributor::instance().noReceiver();
294 /////////////////////////////////////////////////////////////////
295 } // namespace callback
296 ///////////////////////////////////////////////////////////////////
297 /////////////////////////////////////////////////////////////////
299 ///////////////////////////////////////////////////////////////////
300 #endif // ZYPP_CALLBACK_H