StripeKit 0.1.1
Stripe integration toolkit for C++
Loading...
Searching...
No Matches
Callback.h
1/** Callback.h
2 *
3 * Callback compatibility helpers for exactly-once completion semantics.
4 *
5 * @author Hans de Ruiter
6 *
7 * @license See LICENSE.md for details.
8 */
9
10#pragma once
11
12#include <functional>
13#include <mutex>
14#include <utility>
15
16namespace stripekit {
17
18/**
19 * @ingroup async
20 *
21 * Makes a callback safe to hand to code that might fire it more than once.
22 *
23 * StripeKit's callback-form methods must invoke their completion exactly once:
24 * calling it twice corrupts whatever is waiting on it, and never calling it
25 * hangs the request. Adapters wrap the completion in one of these so the rule
26 * holds even on unusual error paths.
27 *
28 * @code
29 * auto once = std::make_shared<stripekit::OnceCallback<Result>>(std::move(completion));
30 * transport.send(request, [once](Result result) { once->invoke(std::move(result)); });
31 * @endcode
32 *
33 * Safe to call from several threads at once.
34 *
35 * @tparam Args Argument types the wrapped callback takes.
36 *
37 * @sa @ref writing_an_adapter
38 */
39template <typename... Args>
41public:
42 /** Signature of the wrapped callback. */
43 using Callback = std::function<void(Args...)>;
44
45 /**
46 * Wraps a callback.
47 *
48 * @param callback The callback to guard. May be empty, in which case
49 * invoke() still reports the first call but does nothing.
50 */
51 explicit OnceCallback(Callback callback) : callback_fn(std::move(callback)) {}
52
53 /**
54 * Calls the wrapped callback, unless it has already been called.
55 *
56 * @param args Arguments forwarded to the callback.
57 * @return True if this call ran the callback; false if it had already run,
58 * in which case the arguments are discarded.
59 */
60 bool invoke(Args... args) {
61 Callback callback_copy;
62 {
63 std::lock_guard<std::mutex> lock(mutex);
64 if (invoked) {
65 return false;
66 }
67 invoked = true;
68 callback_copy = callback_fn;
69 }
70
71 if (callback_copy) {
72 callback_copy(std::forward<Args>(args)...);
73 }
74
75 return true;
76 }
77
78 /**
79 * Reports whether the callback has run.
80 *
81 * @return True once invoke() has been called.
82 */
83 bool was_invoked() const {
84 std::lock_guard<std::mutex> lock(mutex);
85 return invoked;
86 }
87
88private:
89 mutable std::mutex mutex;
90 bool invoked = false;
91 Callback callback_fn;
92};
93
94} // namespace stripekit
bool invoke(Args... args)
Calls the wrapped callback, unless it has already been called.
Definition Callback.h:60
OnceCallback(Callback callback)
Wraps a callback.
Definition Callback.h:51
bool was_invoked() const
Reports whether the callback has run.
Definition Callback.h:83
std::function< void(Args...)> Callback
Signature of the wrapped callback.
Definition Callback.h:43
Async.h.
Definition Async.h:20