@@ -44,6 +44,110 @@ void ReqWrap<T>::Cancel() {
4444 uv_cancel (reinterpret_cast <uv_req_t *>(&req_));
4545}
4646
47+ /* Below is dark template magic designed to invoke libuv functions that
48+ * initialize uv_req_t instances in a unified fashion, to allow easier
49+ * tracking of active/inactive requests. */
50+
51+ // Invoke a generic libuv function that initializes uv_req_t instances.
52+ // This is, unfortunately, necessary since they come in three different
53+ // variants that can not all be invoked in the same way:
54+ // - int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);
55+ // - int uv_foo(uv_req_t* request, ...);
56+ // - void uv_foo(uv_req_t* request, ...);
57+ template <typename ReqT, typename T>
58+ struct CallLibuvFunction ;
59+
60+ // Detect `int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);`.
61+ template <typename ReqT, typename ... Args>
62+ struct CallLibuvFunction <ReqT, int (*)(uv_loop_t *, ReqT*, Args...)> {
63+ typedef int (*T)(uv_loop_t *, ReqT*, Args...);
64+ template <typename ... PassedArgs>
65+ static int Call (T fn, uv_loop_t * loop, ReqT* req, PassedArgs... args) {
66+ return fn (loop, req, args...);
67+ }
68+ };
69+
70+ // Detect `int uv_foo(uv_req_t* request, ...);`.
71+ template <typename ReqT, typename ... Args>
72+ struct CallLibuvFunction <ReqT, int (*)(ReqT*, Args...)> {
73+ typedef int (*T)(ReqT*, Args...);
74+ template <typename ... PassedArgs>
75+ static int Call (T fn, uv_loop_t * loop, ReqT* req, PassedArgs... args) {
76+ return fn (req, args...);
77+ }
78+ };
79+
80+ // Detect `void uv_foo(uv_req_t* request, ...);`.
81+ template <typename ReqT, typename ... Args>
82+ struct CallLibuvFunction <ReqT, void (*)(ReqT*, Args...)> {
83+ typedef void (*T)(ReqT*, Args...);
84+ template <typename ... PassedArgs>
85+ static int Call (T fn, uv_loop_t * loop, ReqT* req, PassedArgs... args) {
86+ fn (req, args...);
87+ return 0 ;
88+ }
89+ };
90+
91+ // This is slightly darker magic: This template is 'applied' to each parameter
92+ // passed to the libuv function. If the parameter type (aka `T`) is a
93+ // function type, it is assumed that this it is the request callback, and a
94+ // wrapper that calls the original callback is created.
95+ // If not, the parameter is passed through verbatim.
96+ template <typename ReqT, typename T>
97+ struct MakeLibuvRequestCallback {
98+ static T For (ReqWrap<ReqT>* req_wrap, T v) {
99+ static_assert (!std::is_function<T>::value,
100+ " MakeLibuvRequestCallback missed a callback" );
101+ return v;
102+ }
103+ };
104+
105+ // Match the `void callback(uv_req_t*, ...);` signature that all libuv
106+ // callbacks use.
107+ template <typename ReqT, typename ... Args>
108+ struct MakeLibuvRequestCallback <ReqT, void (*)(ReqT*, Args...)> {
109+ typedef void (*T)(ReqT* req, Args... args);
110+
111+ static void Wrapper (ReqT* req, Args... args) {
112+ ReqWrap<ReqT>* req_wrap = ContainerOf (&ReqWrap<ReqT>::req_, req);
113+ T original_callback = reinterpret_cast <T>(req_wrap->original_callback_ );
114+ original_callback (req, args...);
115+ }
116+
117+ static T For (ReqWrap<ReqT>* req_wrap, T v) {
118+ CHECK_EQ (req_wrap->original_callback_ , nullptr );
119+ req_wrap->original_callback_ =
120+ reinterpret_cast <typename ReqWrap<ReqT>::callback_t >(v);
121+ return Wrapper;
122+ }
123+ };
124+
125+ template <typename T>
126+ template <typename LibuvFunction, typename ... Args>
127+ int ReqWrap<T>::Dispatch(LibuvFunction fn, Args... args) {
128+ Dispatched ();
129+
130+ // This expands as:
131+ //
132+ // return fn(env()->event_loop(), req(), arg1, arg2, Wrapper, arg3, ...)
133+ // ^ ^ ^
134+ // | | |
135+ // \-- Omitted if `fn` has no | |
136+ // first `uv_loop_t*` argument | |
137+ // | |
138+ // A function callback whose first argument | |
139+ // matches the libuv request type is replaced ---/ |
140+ // by the `Wrapper` method defined above |
141+ // |
142+ // Other (non-function) arguments are passed -----/
143+ // through verbatim
144+ return CallLibuvFunction<T, LibuvFunction>::Call (
145+ fn,
146+ env ()->event_loop (),
147+ req (),
148+ MakeLibuvRequestCallback<T, Args>::For (this , args)...);
149+ }
150+
47151} // namespace node
48152
49153#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
0 commit comments