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 wheter this ReceiveReport is currently
125 * \li \c whoIsConnected Return a 'ReceiveReport*' to the currently
126 * connected ReceiveReport, or \c NULL if none is connected.
130 { /////////////////////////////////////////////////////////////////
135 virtual ~ReportBase()
140 template<class _Report>
141 class DistributeReport;
144 template<class _Report>
145 struct ReceiveReport : public _Report
147 typedef DistributeReport<_Report> Distributor;
149 virtual ~ReceiveReport()
152 ReceiveReport * whoIsConnected() const
153 { return Distributor::instance().getReceiver(); }
155 bool connected() const
156 { return whoIsConnected() == this; }
159 { Distributor::instance().setReceiver( *this ); }
162 { Distributor::instance().unsetReceiver( *this ); }
164 virtual void reportbegin()
166 virtual void reportend()
171 template<class _Report>
172 struct DistributeReport
175 typedef ReceiveReport<_Report> Receiver;
177 static DistributeReport & instance()
179 static DistributeReport _self;
183 Receiver * getReceiver() const
184 { return _receiver == &_noReceiver ? 0 : _receiver; }
186 void setReceiver( Receiver & rec_r )
187 { _receiver = &rec_r; }
189 void unsetReceiver( Receiver & rec_r )
190 { if ( _receiver == &rec_r ) noReceiver(); }
193 { _receiver = &_noReceiver; }
196 Receiver * operator->()
197 { return _receiver; }
201 : _receiver( &_noReceiver )
203 Receiver _noReceiver;
204 Receiver * _receiver;
208 template<class _Report>
209 struct SendReport : private zypp::base::NonCopyable
211 typedef DistributeReport<_Report> Distributor;
214 { Distributor::instance()->reportbegin(); }
217 { Distributor::instance()->reportend(); }
219 Distributor & operator->()
220 { return Distributor::instance(); }
223 /** Temporarily connect a ReceiveReport then restore the previous one.
225 * Pass the ReceiveReport you want to connect temporarily
226 * to the ctor. The ReceiveReport is connected, a previously
227 * connected ReceiveReport is remembered and re-connected in
230 * struct FooReceive : public callback::ReceiveReport<Foo>
232 * struct FooReceive2 : public callback::ReceiveReport<Foo>
239 * ... // r receiving the report
241 * callback::TempConnect<Foo> temp( r2 );
242 * ...// r2 receiving the report
244 * ...// r receiving the report
247 template<class _Report>
250 typedef ReceiveReport<_Report> Receiver;
251 typedef DistributeReport<_Report> Distributor;
253 TempConnect( Receiver & rec_r )
254 : _oldRec( Distributor::instance().getReceiver() )
262 Distributor::instance().setReceiver( *_oldRec );
264 Distributor::instance().noReceiver();
270 /////////////////////////////////////////////////////////////////
271 } // namespace callback
272 ///////////////////////////////////////////////////////////////////
273 /////////////////////////////////////////////////////////////////
275 ///////////////////////////////////////////////////////////////////
276 #endif // ZYPP_CALLBACK_H