Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmcppdap/include/dap/session.h
Line
Count
Source
1
// Copyright 2019 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#ifndef dap_session_h
16
#define dap_session_h
17
18
#include "future.h"
19
#include "io.h"
20
#include "traits.h"
21
#include "typeinfo.h"
22
#include "typeof.h"
23
24
#include <functional>
25
26
namespace dap {
27
28
// Forward declarations
29
struct Request;
30
struct Response;
31
struct Event;
32
33
////////////////////////////////////////////////////////////////////////////////
34
// Error
35
////////////////////////////////////////////////////////////////////////////////
36
37
// Error represents an error message in response to a DAP request.
38
struct Error {
39
  Error() = default;
40
  Error(const std::string& error);
41
  Error(const char* msg, ...);
42
43
  // operator bool() returns true if there is an error.
44
0
  inline operator bool() const { return message.size() > 0; }
45
46
  std::string message;  // empty represents success.
47
};
48
49
////////////////////////////////////////////////////////////////////////////////
50
// ResponseOrError<T>
51
////////////////////////////////////////////////////////////////////////////////
52
53
// ResponseOrError holds either the response to a DAP request or an error
54
// message.
55
template <typename T>
56
struct ResponseOrError {
57
  using Request = T;
58
59
  inline ResponseOrError() = default;
60
  inline ResponseOrError(const T& response);
61
  inline ResponseOrError(T&& response);
62
  inline ResponseOrError(const Error& error);
63
  inline ResponseOrError(Error&& error);
64
  inline ResponseOrError(const ResponseOrError& other);
65
  inline ResponseOrError(ResponseOrError&& other);
66
67
  inline ResponseOrError& operator=(const ResponseOrError& other);
68
  inline ResponseOrError& operator=(ResponseOrError&& other);
69
70
  T response;
71
  Error error;  // empty represents success.
72
};
73
74
template <typename T>
75
ResponseOrError<T>::ResponseOrError(const T& resp) : response(resp) {}
76
template <typename T>
77
ResponseOrError<T>::ResponseOrError(T&& resp) : response(std::move(resp)) {}
78
template <typename T>
79
ResponseOrError<T>::ResponseOrError(const Error& err) : error(err) {}
80
template <typename T>
81
ResponseOrError<T>::ResponseOrError(Error&& err) : error(std::move(err)) {}
82
template <typename T>
83
ResponseOrError<T>::ResponseOrError(const ResponseOrError& other)
84
    : response(other.response), error(other.error) {}
85
template <typename T>
86
ResponseOrError<T>::ResponseOrError(ResponseOrError&& other)
87
    : response(std::move(other.response)), error(std::move(other.error)) {}
88
template <typename T>
89
ResponseOrError<T>& ResponseOrError<T>::operator=(
90
    const ResponseOrError& other) {
91
  response = other.response;
92
  error = other.error;
93
  return *this;
94
}
95
template <typename T>
96
ResponseOrError<T>& ResponseOrError<T>::operator=(ResponseOrError&& other) {
97
  response = std::move(other.response);
98
  error = std::move(other.error);
99
  return *this;
100
}
101
102
////////////////////////////////////////////////////////////////////////////////
103
// Session
104
////////////////////////////////////////////////////////////////////////////////
105
106
// An enum flag that controls how the Session handles invalid data.
107
enum OnInvalidData {
108
  // Ignore invalid data.
109
  kIgnore,
110
  // Close the underlying reader when invalid data is received.
111
  kClose,
112
};
113
114
// Session implements a DAP client or server endpoint.
115
// The general usage is as follows:
116
// (1) Create a session with Session::create().
117
// (2) Register request and event handlers with registerHandler().
118
// (3) Optionally register a protocol error handler with onError().
119
// (3) Bind the session to the remote endpoint with bind().
120
// (4) Send requests or events with send().
121
class Session {
122
  template <typename F, int N>
123
  using ParamType = traits::ParameterType<F, N>;
124
125
  template <typename T>
126
  using IsRequest = traits::EnableIfIsType<dap::Request, T>;
127
128
  template <typename T>
129
  using IsEvent = traits::EnableIfIsType<dap::Event, T>;
130
131
  template <typename F>
132
  using IsRequestHandlerWithoutCallback = traits::EnableIf<
133
      traits::CompatibleWith<F, std::function<void(dap::Request)>>::value>;
134
135
  template <typename F, typename CallbackType>
136
  using IsRequestHandlerWithCallback = traits::EnableIf<traits::CompatibleWith<
137
      F,
138
      std::function<void(dap::Request, std::function<void(CallbackType)>)>>::
139
                                                            value>;
140
141
 public:
142
  virtual ~Session();
143
144
  // ErrorHandler is the type of callback function used for reporting protocol
145
  // errors.
146
  using ErrorHandler = std::function<void(const char*)>;
147
148
  // ClosedHandler is the type of callback function used to signal that a
149
  // connected endpoint has closed.
150
  using ClosedHandler = std::function<void()>;
151
152
  // create() constructs and returns a new Session.
153
  static std::unique_ptr<Session> create();
154
155
  // Sets how the Session handles invalid data.
156
  virtual void setOnInvalidData(OnInvalidData) = 0;
157
158
  // onError() registers a error handler that will be called whenever a protocol
159
  // error is encountered.
160
  // Only one error handler can be bound at any given time, and later calls
161
  // will replace the existing error handler.
162
  virtual void onError(const ErrorHandler&) = 0;
163
164
  // registerHandler() registers a request handler for a specific request type.
165
  // The function F must have one of the following signatures:
166
  //   ResponseOrError<ResponseType>(const RequestType&)
167
  //   ResponseType(const RequestType&)
168
  //   Error(const RequestType&)
169
  template <typename F, typename RequestType = ParamType<F, 0>>
170
  inline IsRequestHandlerWithoutCallback<F> registerHandler(F&& handler);
171
172
  // registerHandler() registers a request handler for a specific request type.
173
  // The handler has a response callback function for the second argument of the
174
  // handler function. This callback may be called after the handler has
175
  // returned.
176
  // The function F must have the following signature:
177
  //   void(const RequestType& request,
178
  //        std::function<void(ResponseType)> response)
179
  template <typename F,
180
            typename RequestType = ParamType<F, 0>,
181
            typename ResponseType = typename RequestType::Response>
182
  inline IsRequestHandlerWithCallback<F, ResponseType> registerHandler(
183
      F&& handler);
184
185
  // registerHandler() registers a request handler for a specific request type.
186
  // The handler has a response callback function for the second argument of the
187
  // handler function. This callback may be called after the handler has
188
  // returned.
189
  // The function F must have the following signature:
190
  //   void(const RequestType& request,
191
  //        std::function<void(ResponseOrError<ResponseType>)> response)
192
  template <typename F,
193
            typename RequestType = ParamType<F, 0>,
194
            typename ResponseType = typename RequestType::Response>
195
  inline IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>
196
  registerHandler(F&& handler);
197
198
  // registerHandler() registers a event handler for a specific event type.
199
  // The function F must have the following signature:
200
  //   void(const EventType&)
201
  template <typename F, typename EventType = ParamType<F, 0>>
202
  inline IsEvent<EventType> registerHandler(F&& handler);
203
204
  // registerSentHandler() registers the function F to be called when a response
205
  // of the specific type has been sent.
206
  // The function F must have the following signature:
207
  //   void(const ResponseOrError<ResponseType>&)
208
  template <typename F,
209
            typename ResponseType = typename ParamType<F, 0>::Request>
210
  inline void registerSentHandler(F&& handler);
211
212
  // send() sends the request to the connected endpoint and returns a
213
  // future that is assigned the request response or error.
214
  template <typename T, typename = IsRequest<T>>
215
  future<ResponseOrError<typename T::Response>> send(const T& request);
216
217
  // send() sends the event to the connected endpoint.
218
  template <typename T, typename = IsEvent<T>>
219
  void send(const T& event);
220
221
  // bind() connects this Session to an endpoint using connect(), and then
222
  // starts processing incoming messages with startProcessingMessages().
223
  // onClose is the optional callback which will be called when the session
224
  // endpoint has been closed.
225
  inline void bind(const std::shared_ptr<Reader>& reader,
226
                   const std::shared_ptr<Writer>& writer,
227
                   const ClosedHandler& onClose);
228
  inline void bind(const std::shared_ptr<ReaderWriter>& readerWriter,
229
                   const ClosedHandler& onClose);
230
231
  //////////////////////////////////////////////////////////////////////////////
232
  // Note:
233
  // Methods and members below this point are for advanced usage, and are more
234
  // likely to change signature than the methods above.
235
  // The methods above this point should be sufficient for most use cases.
236
  //////////////////////////////////////////////////////////////////////////////
237
238
  // connect() connects this Session to an endpoint.
239
  // connect() can only be called once. Repeated calls will raise an error, but
240
  // otherwise will do nothing.
241
  // Note: This method is used for explicit control over message handling.
242
  //       Most users will use bind() instead of calling this method directly.
243
  virtual void connect(const std::shared_ptr<Reader>&,
244
                       const std::shared_ptr<Writer>&) = 0;
245
  inline void connect(const std::shared_ptr<ReaderWriter>&);
246
247
  // startProcessingMessages() starts a new thread to receive and dispatch
248
  // incoming messages.
249
  // onClose is the optional callback which will be called when the session
250
  // endpoint has been closed.
251
  // Note: This method is used for explicit control over message handling.
252
  //       Most users will use bind() instead of calling this method directly.
253
  virtual void startProcessingMessages(const ClosedHandler& onClose = {}) = 0;
254
255
  // getPayload() blocks until the next incoming message is received, returning
256
  // the payload or an empty function if the connection was lost. The returned
257
  // payload is function that can be called on any thread to dispatch the
258
  // message to the Session handler.
259
  // Note: This method is used for explicit control over message handling.
260
  //       Most users will use bind() instead of calling this method directly.
261
  virtual std::function<void()> getPayload() = 0;
262
263
  // The callback function type called when a request handler is invoked, and
264
  // the request returns a successful result.
265
  // 'responseTypeInfo' is the type information of the response data structure.
266
  // 'responseData' is a pointer to response payload data.
267
  using RequestHandlerSuccessCallback =
268
      std::function<void(const TypeInfo* responseTypeInfo,
269
                         const void* responseData)>;
270
271
  // The callback function type used to notify when a DAP request fails.
272
  // 'responseTypeInfo' is the type information of the response data structure.
273
  // 'message' is the error message
274
  using RequestHandlerErrorCallback =
275
      std::function<void(const TypeInfo* responseTypeInfo,
276
                         const Error& message)>;
277
278
  // The callback function type used to invoke a request handler.
279
  // 'request' is a pointer to the request data structure
280
  // 'onSuccess' is the function to call if the request completed succesfully.
281
  // 'onError' is the function to call if the request failed.
282
  // For each call of the request handler, 'onSuccess' or 'onError' must be
283
  // called exactly once.
284
  using GenericRequestHandler =
285
      std::function<void(const void* request,
286
                         const RequestHandlerSuccessCallback& onSuccess,
287
                         const RequestHandlerErrorCallback& onError)>;
288
289
  // The callback function type used to handle a response to a request.
290
  // 'response' is a pointer to the response data structure. May be nullptr.
291
  // 'error' is a pointer to the reponse error message. May be nullptr.
292
  // One of 'data' or 'error' will be nullptr.
293
  using GenericResponseHandler =
294
      std::function<void(const void* response, const Error* error)>;
295
296
  // The callback function type used to handle an event.
297
  // 'event' is a pointer to the event data structure.
298
  using GenericEventHandler = std::function<void(const void* event)>;
299
300
  // The callback function type used to notify when a response has been sent
301
  // from this session endpoint.
302
  // 'response' is a pointer to the response data structure.
303
  // 'error' is a pointer to the reponse error message. May be nullptr.
304
  using GenericResponseSentHandler =
305
      std::function<void(const void* response, const Error* error)>;
306
307
  // registerHandler() registers 'handler' as the request handler callback for
308
  // requests of the type 'typeinfo'.
309
  virtual void registerHandler(const TypeInfo* typeinfo,
310
                               const GenericRequestHandler& handler) = 0;
311
312
  // registerHandler() registers 'handler' as the event handler callback for
313
  // events of the type 'typeinfo'.
314
  virtual void registerHandler(const TypeInfo* typeinfo,
315
                               const GenericEventHandler& handler) = 0;
316
317
  // registerHandler() registers 'handler' as the response-sent handler function
318
  // which is called whenever a response of the type 'typeinfo' is sent from
319
  // this session endpoint.
320
  virtual void registerHandler(const TypeInfo* typeinfo,
321
                               const GenericResponseSentHandler& handler) = 0;
322
323
  // send() sends a request to the remote endpoint.
324
  // 'requestTypeInfo' is the type info of the request data structure.
325
  // 'requestTypeInfo' is the type info of the response data structure.
326
  // 'request' is a pointer to the request data structure.
327
  // 'responseHandler' is the handler function for the response.
328
  virtual bool send(const dap::TypeInfo* requestTypeInfo,
329
                    const dap::TypeInfo* responseTypeInfo,
330
                    const void* request,
331
                    const GenericResponseHandler& responseHandler) = 0;
332
333
  // send() sends an event to the remote endpoint.
334
  // 'eventTypeInfo' is the type info for the event data structure.
335
  // 'event' is a pointer to the event data structure.
336
  virtual bool send(const TypeInfo* eventTypeInfo, const void* event) = 0;
337
};
338
339
template <typename F, typename RequestType>
340
Session::IsRequestHandlerWithoutCallback<F> Session::registerHandler(
341
    F&& handler) {
342
  using ResponseType = typename RequestType::Response;
343
  const TypeInfo* typeinfo = TypeOf<RequestType>::type();
344
  registerHandler(typeinfo,
345
                  [handler](const void* args,
346
                            const RequestHandlerSuccessCallback& onSuccess,
347
                            const RequestHandlerErrorCallback& onError) {
348
                    ResponseOrError<ResponseType> res =
349
                        handler(*reinterpret_cast<const RequestType*>(args));
350
                    if (res.error) {
351
                      onError(TypeOf<ResponseType>::type(), res.error);
352
                    } else {
353
                      onSuccess(TypeOf<ResponseType>::type(), &res.response);
354
                    }
355
                  });
356
}
357
358
template <typename F, typename RequestType, typename ResponseType>
359
Session::IsRequestHandlerWithCallback<F, ResponseType> Session::registerHandler(
360
    F&& handler) {
361
  using CallbackType = ParamType<F, 1>;
362
  registerHandler(
363
      TypeOf<RequestType>::type(),
364
      [handler](const void* args,
365
                const RequestHandlerSuccessCallback& onSuccess,
366
                const RequestHandlerErrorCallback&) {
367
        CallbackType responseCallback = [onSuccess](const ResponseType& res) {
368
          onSuccess(TypeOf<ResponseType>::type(), &res);
369
        };
370
        handler(*reinterpret_cast<const RequestType*>(args), responseCallback);
371
      });
372
}
373
374
template <typename F, typename RequestType, typename ResponseType>
375
Session::IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>
376
Session::registerHandler(F&& handler) {
377
  using CallbackType = ParamType<F, 1>;
378
  registerHandler(
379
      TypeOf<RequestType>::type(),
380
      [handler](const void* args,
381
                const RequestHandlerSuccessCallback& onSuccess,
382
                const RequestHandlerErrorCallback& onError) {
383
        CallbackType responseCallback =
384
            [onError, onSuccess](const ResponseOrError<ResponseType>& res) {
385
              if (res.error) {
386
                onError(TypeOf<ResponseType>::type(), res.error);
387
              } else {
388
                onSuccess(TypeOf<ResponseType>::type(), &res.response);
389
              }
390
            };
391
        handler(*reinterpret_cast<const RequestType*>(args), responseCallback);
392
      });
393
}
394
395
template <typename F, typename T>
396
Session::IsEvent<T> Session::registerHandler(F&& handler) {
397
  auto cb = [handler](const void* args) {
398
    handler(*reinterpret_cast<const T*>(args));
399
  };
400
  const TypeInfo* typeinfo = TypeOf<T>::type();
401
  registerHandler(typeinfo, cb);
402
}
403
404
template <typename F, typename T>
405
void Session::registerSentHandler(F&& handler) {
406
  auto cb = [handler](const void* response, const Error* error) {
407
    if (error != nullptr) {
408
      handler(ResponseOrError<T>(*error));
409
    } else {
410
      handler(ResponseOrError<T>(*reinterpret_cast<const T*>(response)));
411
    }
412
  };
413
  const TypeInfo* typeinfo = TypeOf<T>::type();
414
  registerHandler(typeinfo, cb);
415
}
416
417
template <typename T, typename>
418
future<ResponseOrError<typename T::Response>> Session::send(const T& request) {
419
  using Response = typename T::Response;
420
  promise<ResponseOrError<Response>> promise;
421
  auto sent = send(TypeOf<T>::type(), TypeOf<Response>::type(), &request,
422
                   [=](const void* result, const Error* error) {
423
                     if (error != nullptr) {
424
                       promise.set_value(ResponseOrError<Response>(*error));
425
                     } else {
426
                       promise.set_value(ResponseOrError<Response>(
427
                           *reinterpret_cast<const Response*>(result)));
428
                     }
429
                   });
430
  if (!sent) {
431
    promise.set_value(Error("Failed to send request"));
432
  }
433
  return promise.get_future();
434
}
435
436
template <typename T, typename>
437
void Session::send(const T& event) {
438
  const TypeInfo* typeinfo = TypeOf<T>::type();
439
  send(typeinfo, &event);
440
}
441
442
0
void Session::connect(const std::shared_ptr<ReaderWriter>& rw) {
443
0
  connect(rw, rw);
444
0
}
445
446
void Session::bind(const std::shared_ptr<dap::Reader>& r,
447
                   const std::shared_ptr<dap::Writer>& w,
448
0
                   const ClosedHandler& onClose = {}) {
449
0
  connect(r, w);
450
0
  startProcessingMessages(onClose);
451
0
}
452
453
void Session::bind(const std::shared_ptr<ReaderWriter>& rw,
454
0
                   const ClosedHandler& onClose = {}) {
455
0
  bind(rw, rw, onClose);
456
0
}
457
458
}  // namespace dap
459
460
#endif  // dap_session_h