[cppdap] Merge from upstream for response cb fixes

Change-Id: Id4faf9ffce7babf93fec89bf9ba67f323edf126b
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2ec3ac0..47cb5df 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -221,6 +221,7 @@
         ${CPPDAP_SRC_DIR}/rwmutex_test.cpp
         ${CPPDAP_SRC_DIR}/session_test.cpp
         ${CPPDAP_SRC_DIR}/socket_test.cpp
+        ${CPPDAP_SRC_DIR}/traits_test.cpp
         ${CPPDAP_SRC_DIR}/typeinfo_test.cpp
         ${CPPDAP_SRC_DIR}/variant_test.cpp
         ${CPPDAP_GOOGLETEST_DIR}/googletest/src/gtest-all.cc
diff --git a/include/dap/protocol.h b/include/dap/protocol.h
index c45d421..0d13547 100644
--- a/include/dap/protocol.h
+++ b/include/dap/protocol.h
@@ -15,7 +15,7 @@
 // Generated with protocol_gen.go -- do not edit this file.
 //   go run scripts/protocol_gen/protocol_gen.go
 //
-// DAP version 1.41.0
+// DAP version 1.43.0
 
 #ifndef dap_protocol_h
 #define dap_protocol_h
@@ -102,7 +102,7 @@
   // If sourceReference > 0 the contents of the source must be retrieved through
   // the SourceRequest (even if a path is specified). A sourceReference is only
   // valid for a session, so it must not be used to persist a source. The value
-  // should be less than or equal to 2147483647 (2^31 - 1).
+  // should be less than or equal to 2147483647 (2^31-1).
   optional<integer> sourceReference;
   // An optional list of sources that are related to this source. These may be
   // the source that generated this source.
@@ -269,16 +269,20 @@
 
 DAP_DECLARE_STRUCT_TYPEINFO(ColumnDescriptor);
 
-// An ExceptionBreakpointsFilter is shown in the UI as an option for configuring
-// how exceptions are dealt with.
+// An ExceptionBreakpointsFilter is shown in the UI as an filter option for
+// configuring how exceptions are dealt with.
 struct ExceptionBreakpointsFilter {
-  // Initial value of the filter. If not specified a value 'false' is assumed.
+  // Initial value of the filter option. If not specified a value 'false' is
+  // assumed.
   optional<boolean> def;
-  // The internal ID of the filter. This value is passed to the
-  // setExceptionBreakpoints request.
+  // The internal ID of the filter option. This value is passed to the
+  // 'setExceptionBreakpoints' request.
   string filter;
-  // The name of the filter. This will be shown in the UI.
+  // The name of the filter option. This will be shown in the UI.
   string label;
+  // Controls whether a condition can be specified for this filter option. If
+  // false or missing, a condition can not be set.
+  optional<boolean> supportsCondition;
 };
 
 DAP_DECLARE_STRUCT_TYPEINFO(ExceptionBreakpointsFilter);
@@ -290,7 +294,8 @@
   // The set of characters that should trigger completion in a REPL. If not
   // specified, the UI should assume the '.' character.
   optional<array<string>> completionTriggerCharacters;
-  // Available filters or options for the setExceptionBreakpoints request.
+  // Available exception filter options for the 'setExceptionBreakpoints'
+  // request.
   optional<array<ExceptionBreakpointsFilter>> exceptionBreakpointFilters;
   // The debug adapter supports the 'terminateDebuggee' attribute on the
   // 'disconnect' request.
@@ -321,6 +326,9 @@
   // The debug adapter supports a (side effect free) evaluate request for data
   // hovers.
   optional<boolean> supportsEvaluateForHovers;
+  // The debug adapter supports 'filterOptions' as an argument on the
+  // 'setExceptionBreakpoints' request.
+  optional<boolean> supportsExceptionFilterOptions;
   // The debug adapter supports the 'exceptionInfo' request.
   optional<boolean> supportsExceptionInfoRequest;
   // The debug adapter supports 'exceptionOptions' on the
@@ -703,7 +711,7 @@
   // The number of indexed child variables.
   // The client can use this optional information to present the variables in a
   // paged UI and fetch them in chunks. The value should be less than or equal
-  // to 2147483647 (2^31 - 1).
+  // to 2147483647 (2^31-1).
   optional<integer> indexedVariables;
   // Optional memory reference to a location appropriate for this result.
   // For pointer type eval results, this is generally a reference to the memory
@@ -714,7 +722,7 @@
   // The number of named child variables.
   // The client can use this optional information to present the variables in a
   // paged UI and fetch them in chunks. The value should be less than or equal
-  // to 2147483647 (2^31 - 1).
+  // to 2147483647 (2^31-1).
   optional<integer> namedVariables;
   // Properties of a evaluate result that can be used to determine how to render
   // the result in the UI.
@@ -729,7 +737,7 @@
   // If variablesReference is > 0, the evaluate result is structured and its
   // children can be retrieved by passing variablesReference to the
   // VariablesRequest. The value should be less than or equal to 2147483647
-  // (2^31 - 1).
+  // (2^31-1).
   integer variablesReference;
 };
 
@@ -902,7 +910,8 @@
   // The set of characters that should trigger completion in a REPL. If not
   // specified, the UI should assume the '.' character.
   optional<array<string>> completionTriggerCharacters;
-  // Available filters or options for the setExceptionBreakpoints request.
+  // Available exception filter options for the 'setExceptionBreakpoints'
+  // request.
   optional<array<ExceptionBreakpointsFilter>> exceptionBreakpointFilters;
   // The debug adapter supports the 'terminateDebuggee' attribute on the
   // 'disconnect' request.
@@ -933,6 +942,9 @@
   // The debug adapter supports a (side effect free) evaluate request for data
   // hovers.
   optional<boolean> supportsEvaluateForHovers;
+  // The debug adapter supports 'filterOptions' as an argument on the
+  // 'setExceptionBreakpoints' request.
+  optional<boolean> supportsExceptionFilterOptions;
   // The debug adapter supports the 'exceptionInfo' request.
   optional<boolean> supportsExceptionInfoRequest;
   // The debug adapter supports 'exceptionOptions' on the
@@ -1015,6 +1027,8 @@
   // May be one of the following enumeration values:
   // 'path', 'uri'
   optional<string> pathFormat;
+  // Client supports the invalidated event.
+  optional<boolean> supportsInvalidatedEvent;
   // Client supports memory references.
   optional<boolean> supportsMemoryReferences;
   // Client supports progress reporting.
@@ -1049,6 +1063,35 @@
 
 DAP_DECLARE_STRUCT_TYPEINFO(InitializedEvent);
 
+// Logical areas that can be invalidated by the 'invalidated' event.
+struct InvalidatedAreas {};
+
+DAP_DECLARE_STRUCT_TYPEINFO(InvalidatedAreas);
+
+// This event signals that some state in the debug adapter has changed and
+// requires that the client needs to re-render the data snapshot previously
+// requested. Debug adapters do not have to emit this event for runtime changes
+// like stopped or thread events because in that case the client refetches the
+// new state anyway. But the event can be used for example to refresh the UI
+// after rendering formatting has changed in the debug adapter. This event
+// should only be sent if the debug adapter has received a value true for the
+// 'supportsInvalidatedEvent' capability of the 'initialize' request.
+struct InvalidatedEvent : public Event {
+  // Optional set of logical areas that got invalidated. This property has a
+  // hint characteristic: a client can only be expected to make a 'best effort'
+  // in honouring the areas but there are no guarantees. If this property is
+  // missing, empty, or if values are not understand the client should assume a
+  // single value 'all'.
+  optional<array<InvalidatedAreas>> areas;
+  // If specified, the client only needs to refetch data related to this stack
+  // frame (and the 'threadId' is ignored).
+  optional<integer> stackFrameId;
+  // If specified, the client only needs to refetch data related to this thread.
+  optional<integer> threadId;
+};
+
+DAP_DECLARE_STRUCT_TYPEINFO(InvalidatedEvent);
+
 // Response to 'launch' request. This is just an acknowledgement, so no body
 // field is required.
 struct LaunchResponse : public Response {};
@@ -1241,7 +1284,7 @@
   // If an attribute 'variablesReference' exists and its value is > 0, the
   // output contains objects which can be retrieved by passing
   // 'variablesReference' to the 'variables' request. The value should be less
-  // than or equal to 2147483647 (2^31 - 1).
+  // than or equal to 2147483647 (2^31-1).
   optional<integer> variablesReference;
 };
 
@@ -1327,7 +1370,7 @@
   // request until the request has been either completed or cancelled. If the
   // request ID is omitted, the progress report is assumed to be related to some
   // general activity of the debug adapter.
-  optional<number> requestId;
+  optional<integer> requestId;
   // Mandatory (short) title of the progress reporting. Shown in the UI to
   // describe the long running operation.
   string title;
@@ -1439,11 +1482,11 @@
 
 // Response to 'runInTerminal' request.
 struct RunInTerminalResponse : public Response {
-  // The process ID. The value should be less than or equal to 2147483647 (2^31
-  // - 1).
+  // The process ID. The value should be less than or equal to 2147483647
+  // (2^31-1).
   optional<integer> processId;
   // The process ID of the terminal shell. The value should be less than or
-  // equal to 2147483647 (2^31 - 1).
+  // equal to 2147483647 (2^31-1).
   optional<integer> shellProcessId;
 };
 
@@ -1458,7 +1501,8 @@
   using Response = RunInTerminalResponse;
   // List of arguments. The first argument is the command to run.
   array<string> args;
-  // Working directory of the command.
+  // Working directory for the command. For non-empty, valid paths this
+  // typically results in execution of a change directory command.
   string cwd;
   // Environment key-value pairs that are added to or removed from the default
   // environment.
@@ -1663,6 +1707,20 @@
 
 DAP_DECLARE_STRUCT_TYPEINFO(ExceptionOptions);
 
+// An ExceptionFilterOptions is used to specify an exception filter together
+// with a condition for the setExceptionsFilter request.
+struct ExceptionFilterOptions {
+  // An optional expression for conditional exceptions.
+  // The exception will break into the debugger if the result of the condition
+  // is true.
+  optional<string> condition;
+  // ID of an exception filter returned by the 'exceptionBreakpointFilters'
+  // capability.
+  string filterId;
+};
+
+DAP_DECLARE_STRUCT_TYPEINFO(ExceptionFilterOptions);
+
 // The request configures the debuggers response to thrown exceptions.
 // If an exception is configured to break, a 'stopped' event is fired (with
 // reason 'exception'). Clients should only call this request if the capability
@@ -1673,8 +1731,15 @@
   // The attribute is only honored by a debug adapter if the capability
   // 'supportsExceptionOptions' is true.
   optional<array<ExceptionOptions>> exceptionOptions;
-  // IDs of checked exception options. The set of IDs is returned via the
-  // 'exceptionBreakpointFilters' capability.
+  // Set of exception filters and their options. The set of all possible
+  // exception filters is defined by the 'exceptionBreakpointFilters'
+  // capability. This attribute is only honored by a debug adapter if the
+  // capability 'supportsExceptionFilterOptions' is true. The 'filter' and
+  // 'filterOptions' sets are additive.
+  optional<array<ExceptionFilterOptions>> filterOptions;
+  // Set of exception filters specified by their ID. The set of all possible
+  // exception filters is defined by the 'exceptionBreakpointFilters'
+  // capability. The 'filter' and 'filterOptions' sets are additive.
   array<string> filters;
 };
 
@@ -1685,12 +1750,12 @@
   // The number of indexed child variables.
   // The client can use this optional information to present the variables in a
   // paged UI and fetch them in chunks. The value should be less than or equal
-  // to 2147483647 (2^31 - 1).
+  // to 2147483647 (2^31-1).
   optional<integer> indexedVariables;
   // The number of named child variables.
   // The client can use this optional information to present the variables in a
   // paged UI and fetch them in chunks. The value should be less than or equal
-  // to 2147483647 (2^31 - 1).
+  // to 2147483647 (2^31-1).
   optional<integer> namedVariables;
   // Properties of a value that can be used to determine how to render the
   // result in the UI.
@@ -1704,7 +1769,7 @@
   string value;
   // If variablesReference is > 0, the value is structured and its children can
   // be retrieved by passing variablesReference to the VariablesRequest. The
-  // value should be less than or equal to 2147483647 (2^31 - 1).
+  // value should be less than or equal to 2147483647 (2^31-1).
   optional<integer> variablesReference;
 };
 
@@ -1820,12 +1885,12 @@
   // The number of indexed child variables.
   // The client can use this optional information to present the variables in a
   // paged UI and fetch them in chunks. The value should be less than or equal
-  // to 2147483647 (2^31 - 1).
+  // to 2147483647 (2^31-1).
   optional<integer> indexedVariables;
   // The number of named child variables.
   // The client can use this optional information to present the variables in a
   // paged UI and fetch them in chunks. The value should be less than or equal
-  // to 2147483647 (2^31 - 1).
+  // to 2147483647 (2^31-1).
   optional<integer> namedVariables;
   // The type of the new value. Typically shown in the UI when hovering over the
   // value.
@@ -1834,7 +1899,7 @@
   string value;
   // If variablesReference is > 0, the new value is structured and its children
   // can be retrieved by passing variablesReference to the VariablesRequest. The
-  // value should be less than or equal to 2147483647 (2^31 - 1).
+  // value should be less than or equal to 2147483647 (2^31-1).
   optional<integer> variablesReference;
 };
 
@@ -1924,7 +1989,12 @@
   // stackframes available. This means that there is no location information
   // available.
   array<StackFrame> stackFrames;
-  // The total number of frames available.
+  // The total number of frames available in the stack. If omitted or if
+  // totalFrames is larger than the available frames, a client is expected to
+  // request frames until a request returns less frames than requested (which
+  // indicates the end of the stack). Returning monotonically increasing
+  // totalFrames values for subsequent requests can be used to enforce paging in
+  // the client.
   optional<integer> totalFrames;
 };
 
@@ -1951,7 +2021,16 @@
 
 DAP_DECLARE_STRUCT_TYPEINFO(StackFrameFormat);
 
-// The request returns a stacktrace from the current execution state.
+// The request returns a stacktrace from the current execution state of a given
+// thread. A client can request all stack frames by omitting the startFrame and
+// levels arguments. For performance conscious clients stack frames can be
+// retrieved in a piecemeal way with the startFrame and levels arguments. The
+// response of the stackTrace request may contain a totalFrames property that
+// hints at the total number of frames in the stack. If a client needs this
+// total number upfront, it can issue a request for a single (first) frame and
+// depending on the value of totalFrames decide how to proceed. In any case a
+// client should be prepared to receive less frames than requested, which is an
+// indication that the end of the stack has been reached.
 struct StackTraceRequest : public Request {
   using Response = StackTraceResponse;
   // Specifies details on how to format the stack frames.
diff --git a/include/dap/session.h b/include/dap/session.h
index e06957f..11d5560 100644
--- a/include/dap/session.h
+++ b/include/dap/session.h
@@ -17,6 +17,7 @@
 
 #include "future.h"
 #include "io.h"
+#include "traits.h"
 #include "typeinfo.h"
 #include "typeof.h"
 
@@ -29,33 +30,6 @@
 struct Response;
 struct Event;
 
-// internal functionality
-namespace detail {
-template <typename T>
-struct traits {
-  static constexpr bool isRequest = std::is_base_of<dap::Request, T>::value;
-  static constexpr bool isResponse = std::is_base_of<dap::Response, T>::value;
-  static constexpr bool isEvent = std::is_base_of<dap::Event, T>::value;
-};
-
-// ArgTy<F>::type resolves to the first argument type of the function F.
-// F can be a function, static member function, or lambda.
-template <typename F>
-struct ArgTy {
-  using type = typename ArgTy<decltype(&F::operator())>::type;
-};
-
-template <typename R, typename Arg>
-struct ArgTy<R (*)(Arg)> {
-  using type = typename std::decay<Arg>::type;
-};
-
-template <typename R, typename C, typename Arg>
-struct ArgTy<R (C::*)(Arg) const> {
-  using type = typename std::decay<Arg>::type;
-};
-}  // namespace detail
-
 ////////////////////////////////////////////////////////////////////////////////
 // Error
 ////////////////////////////////////////////////////////////////////////////////
@@ -137,14 +111,24 @@
 // (3) Bind the session to the remote endpoint with bind().
 // (4) Send requests or events with send().
 class Session {
-  template <typename T>
-  using IsRequest = typename std::enable_if<detail::traits<T>::isRequest>::type;
+  template <typename F, int N>
+  using ParamType = traits::ParameterType<F, N>;
 
   template <typename T>
-  using IsEvent = typename std::enable_if<detail::traits<T>::isEvent>::type;
+  using IsRequest = traits::EnableIfIsType<dap::Request, T>;
+
+  template <typename T>
+  using IsEvent = traits::EnableIfIsType<dap::Event, T>;
 
   template <typename F>
-  using ArgTy = typename detail::ArgTy<F>::type;
+  using IsRequestHandlerWithoutCallback = traits::EnableIf<
+      traits::CompatibleWith<F, std::function<void(dap::Request)>>::value>;
+
+  template <typename F, typename CallbackType>
+  using IsRequestHandlerWithCallback = traits::EnableIf<traits::CompatibleWith<
+      F,
+      std::function<void(dap::Request, std::function<void(CallbackType)>)>>::
+                                                            value>;
 
  public:
   virtual ~Session();
@@ -167,20 +151,47 @@
   //   ResponseOrError<ResponseType>(const RequestType&)
   //   ResponseType(const RequestType&)
   //   Error(const RequestType&)
-  template <typename F, typename RequestType = ArgTy<F>>
-  inline IsRequest<RequestType> registerHandler(F&& handler);
+  template <typename F, typename RequestType = ParamType<F, 0>>
+  inline IsRequestHandlerWithoutCallback<F> registerHandler(F&& handler);
+
+  // registerHandler() registers a request handler for a specific request type.
+  // The handler has a response callback function for the second argument of the
+  // handler function. This callback may be called after the handler has
+  // returned.
+  // The function F must have the following signature:
+  //   void(const RequestType& request,
+  //        std::function<void(ResponseType)> response)
+  template <typename F,
+            typename RequestType = ParamType<F, 0>,
+            typename ResponseType = typename RequestType::Response>
+  inline IsRequestHandlerWithCallback<F, ResponseType> registerHandler(
+      F&& handler);
+
+  // registerHandler() registers a request handler for a specific request type.
+  // The handler has a response callback function for the second argument of the
+  // handler function. This callback may be called after the handler has
+  // returned.
+  // The function F must have the following signature:
+  //   void(const RequestType& request,
+  //        std::function<void(ResponseOrError<ResponseType>)> response)
+  template <typename F,
+            typename RequestType = ParamType<F, 0>,
+            typename ResponseType = typename RequestType::Response>
+  inline IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>
+  registerHandler(F&& handler);
 
   // registerHandler() registers a event handler for a specific event type.
   // The function F must have the following signature:
   //   void(const EventType&)
-  template <typename F, typename EventType = ArgTy<F>>
+  template <typename F, typename EventType = ParamType<F, 0>>
   inline IsEvent<EventType> registerHandler(F&& handler);
 
   // registerSentHandler() registers the function F to be called when a response
   // of the specific type has been sent.
   // The function F must have the following signature:
   //   void(const ResponseOrError<ResponseType>&)
-  template <typename F, typename ResponseType = typename ArgTy<F>::Request>
+  template <typename F,
+            typename ResponseType = typename ParamType<F, 0>::Request>
   inline void registerSentHandler(F&& handler);
 
   // send() sends the request to the connected endpoint and returns a
@@ -251,21 +262,57 @@
   virtual bool send(const TypeInfo*, const void* event) = 0;
 };
 
-template <typename F, typename T>
-Session::IsRequest<T> Session::registerHandler(F&& handler) {
-  using ResponseType = typename T::Response;
-  auto cb = [handler](const void* args, const RequestSuccessCallback& onSuccess,
-                      const RequestErrorCallback& onError) {
+template <typename F, typename RequestType>
+Session::IsRequestHandlerWithoutCallback<F> Session::registerHandler(
+    F&& handler) {
+  using ResponseType = typename RequestType::Response;
+  const TypeInfo* typeinfo = TypeOf<RequestType>::type();
+  registerHandler(typeinfo, [handler](const void* args,
+                                      const RequestSuccessCallback& onSuccess,
+                                      const RequestErrorCallback& onError) {
     ResponseOrError<ResponseType> res =
-        handler(*reinterpret_cast<const T*>(args));
+        handler(*reinterpret_cast<const RequestType*>(args));
     if (res.error) {
       onError(TypeOf<ResponseType>::type(), res.error);
     } else {
       onSuccess(TypeOf<ResponseType>::type(), &res.response);
     }
-  };
-  const TypeInfo* typeinfo = TypeOf<T>::type();
-  registerHandler(typeinfo, cb);
+  });
+}
+
+template <typename F, typename RequestType, typename ResponseType>
+Session::IsRequestHandlerWithCallback<F, ResponseType> Session::registerHandler(
+    F&& handler) {
+  using CallbackType = ParamType<F, 1>;
+  registerHandler(
+      TypeOf<RequestType>::type(),
+      [handler](const void* args, const RequestSuccessCallback& onSuccess,
+                const RequestErrorCallback&) {
+        CallbackType responseCallback = [onSuccess](const ResponseType& res) {
+          onSuccess(TypeOf<ResponseType>::type(), &res);
+        };
+        handler(*reinterpret_cast<const RequestType*>(args), responseCallback);
+      });
+}
+
+template <typename F, typename RequestType, typename ResponseType>
+Session::IsRequestHandlerWithCallback<F, ResponseOrError<ResponseType>>
+Session::registerHandler(F&& handler) {
+  using CallbackType = ParamType<F, 1>;
+  registerHandler(
+      TypeOf<RequestType>::type(),
+      [handler](const void* args, const RequestSuccessCallback& onSuccess,
+                const RequestErrorCallback& onError) {
+        CallbackType responseCallback =
+            [onError, onSuccess](const ResponseOrError<ResponseType>& res) {
+              if (res.error) {
+                onError(TypeOf<ResponseType>::type(), res.error);
+              } else {
+                onSuccess(TypeOf<ResponseType>::type(), &res.response);
+              }
+            };
+        handler(*reinterpret_cast<const RequestType*>(args), responseCallback);
+      });
 }
 
 template <typename F, typename T>
diff --git a/include/dap/traits.h b/include/dap/traits.h
new file mode 100644
index 0000000..cbc7d39
--- /dev/null
+++ b/include/dap/traits.h
@@ -0,0 +1,159 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef dap_traits_h
+#define dap_traits_h
+
+#include <tuple>
+#include <type_traits>
+
+namespace dap {
+namespace traits {
+
+// NthTypeOf returns the `N`th type in `Types`
+template <int N, typename... Types>
+using NthTypeOf = typename std::tuple_element<N, std::tuple<Types...>>::type;
+
+// `IsTypeOrDerived<BASE, T>::value` is true iff `T` is of type `BASE`, or
+// derives from `BASE`.
+template <typename BASE, typename T>
+using IsTypeOrDerived = std::integral_constant<
+    bool,
+    std::is_base_of<BASE, typename std::decay<T>::type>::value ||
+        std::is_same<BASE, typename std::decay<T>::type>::value>;
+
+// `EachIsTypeOrDerived<N, BASES, TYPES>::value` is true iff all of the types in
+// the std::tuple `TYPES` is of, or derives from the corresponding indexed type
+// in the std::tuple `BASES`.
+// `N` must be equal to the number of types in both the std::tuple `BASES` and
+// `TYPES`.
+template <int N, typename BASES, typename TYPES>
+struct EachIsTypeOrDerived {
+  using base = typename std::tuple_element<N - 1, BASES>::type;
+  using type = typename std::tuple_element<N - 1, TYPES>::type;
+  using last_matches = IsTypeOrDerived<base, type>;
+  using others_match = EachIsTypeOrDerived<N - 1, BASES, TYPES>;
+  static constexpr bool value = last_matches::value && others_match::value;
+};
+
+// EachIsTypeOrDerived specialization for N = 1
+template <typename BASES, typename TYPES>
+struct EachIsTypeOrDerived<1, BASES, TYPES> {
+  using base = typename std::tuple_element<0, BASES>::type;
+  using type = typename std::tuple_element<0, TYPES>::type;
+  static constexpr bool value = IsTypeOrDerived<base, type>::value;
+};
+
+// EachIsTypeOrDerived specialization for N = 0
+template <typename BASES, typename TYPES>
+struct EachIsTypeOrDerived<0, BASES, TYPES> {
+  static constexpr bool value = true;
+};
+
+// Signature describes the signature of a function.
+template <typename RETURN, typename... PARAMETERS>
+struct Signature {
+  // The return type of the function signature
+  using ret = RETURN;
+  // The parameters of the function signature held in a std::tuple
+  using parameters = std::tuple<PARAMETERS...>;
+  // The type of the Nth parameter of function signature
+  template <std::size_t N>
+  using parameter = NthTypeOf<N, PARAMETERS...>;
+  // The total number of parameters
+  static constexpr std::size_t parameter_count = sizeof...(PARAMETERS);
+};
+
+// SignatureOf is a traits helper that infers the signature of the function,
+// method, static method, lambda, or function-like object `F`.
+template <typename F>
+struct SignatureOf {
+  // The signature of the function-like object `F`
+  using type = typename SignatureOf<decltype(&F::operator())>::type;
+};
+
+// SignatureOf specialization for a regular function or static method.
+template <typename R, typename... ARGS>
+struct SignatureOf<R (*)(ARGS...)> {
+  // The signature of the function-like object `F`
+  using type = Signature<typename std::decay<R>::type,
+                         typename std::decay<ARGS>::type...>;
+};
+
+// SignatureOf specialization for a non-static method.
+template <typename R, typename C, typename... ARGS>
+struct SignatureOf<R (C::*)(ARGS...)> {
+  // The signature of the function-like object `F`
+  using type = Signature<typename std::decay<R>::type,
+                         typename std::decay<ARGS>::type...>;
+};
+
+// SignatureOf specialization for a non-static, const method.
+template <typename R, typename C, typename... ARGS>
+struct SignatureOf<R (C::*)(ARGS...) const> {
+  // The signature of the function-like object `F`
+  using type = Signature<typename std::decay<R>::type,
+                         typename std::decay<ARGS>::type...>;
+};
+
+// SignatureOfT is an alias to `typename SignatureOf<F>::type`.
+template <typename F>
+using SignatureOfT = typename SignatureOf<F>::type;
+
+// ParameterType is an alias to `typename SignatureOf<F>::type::parameter<N>`.
+template <typename F, std::size_t N>
+using ParameterType = typename SignatureOfT<F>::template parameter<N>;
+
+// `HasSignature<F, S>::value` is true iff the function-like `F` has a matching
+// signature to the function-like `S`.
+template <typename F, typename S>
+using HasSignature = std::integral_constant<
+    bool,
+    std::is_same<SignatureOfT<F>, SignatureOfT<S>>::value>;
+
+// `Min<A, B>::value` resolves to the smaller value of A and B.
+template <std::size_t A, std::size_t B>
+using Min = std::integral_constant<std::size_t, (A < B ? A : B)>;
+
+// `CompatibleWith<F, S>::value` is true iff the function-like `F`
+// can be called with the argument types of the function-like `S`. Return type
+// of the two functions are not considered.
+template <typename F, typename S>
+using CompatibleWith = std::integral_constant<
+    bool,
+    (SignatureOfT<S>::parameter_count == SignatureOfT<F>::parameter_count) &&
+        EachIsTypeOrDerived<Min<SignatureOfT<S>::parameter_count,
+                                SignatureOfT<F>::parameter_count>::value,
+                            typename SignatureOfT<S>::parameters,
+                            typename SignatureOfT<F>::parameters>::value>;
+
+// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
+// invalid type.
+template <bool CONDITION, typename T = void>
+using EnableIf = typename std::enable_if<CONDITION, T>::type;
+
+// If `BASE` is a base of `T` then EnableIfIsType resolves to type `TRUE`,
+// otherwise an invalid type.
+template <typename BASE, typename T, typename TRUE = void>
+using EnableIfIsType = EnableIf<IsTypeOrDerived<BASE, T>::value, TRUE>;
+
+// If the function-like `F` has a matching signature to the function-like `S`
+// then EnableIfHasSignature resolves to type `TRUE`, otherwise an invalid type.
+template <typename F, typename S, typename TRUE = void>
+using EnableIfHasSignature = EnableIf<HasSignature<F, S>::value, TRUE>;
+
+}  // namespace traits
+}  // namespace dap
+
+#endif  // dap_traits_h
diff --git a/license-checker.cfg b/license-checker.cfg
index aa86ef2..e28ee40 100644
--- a/license-checker.cfg
+++ b/license-checker.cfg
@@ -1,5 +1,6 @@
 {
     "licenses": [
+        "Apache-2.0",
         "Apache-2.0-Header"
     ],
     "paths": [
@@ -17,7 +18,8 @@
                 "fuzz/**",
                 "kokoro/**.cfg",
                 "third_party/googletest/**",
-                "third_party/json/**"
+                "third_party/json/**",
+                "third_party/rapidjson/**"
             ]
         }
     ]
diff --git a/src/protocol_events.cpp b/src/protocol_events.cpp
index 5be9e9f..3743481 100644
--- a/src/protocol_events.cpp
+++ b/src/protocol_events.cpp
@@ -15,7 +15,7 @@
 // Generated with protocol_gen.go -- do not edit this file.
 //   go run scripts/protocol_gen/protocol_gen.go
 //
-// DAP version 1.41.0
+// DAP version 1.43.0
 
 #include "dap/protocol.h"
 
@@ -42,6 +42,12 @@
 
 DAP_IMPLEMENT_STRUCT_TYPEINFO(InitializedEvent, "initialized");
 
+DAP_IMPLEMENT_STRUCT_TYPEINFO(InvalidatedEvent,
+                              "invalidated",
+                              DAP_FIELD(areas, "areas"),
+                              DAP_FIELD(stackFrameId, "stackFrameId"),
+                              DAP_FIELD(threadId, "threadId"));
+
 DAP_IMPLEMENT_STRUCT_TYPEINFO(LoadedSourceEvent,
                               "loadedSource",
                               DAP_FIELD(reason, "reason"),
diff --git a/src/protocol_requests.cpp b/src/protocol_requests.cpp
index bdfb7c3..c76b5ff 100644
--- a/src/protocol_requests.cpp
+++ b/src/protocol_requests.cpp
@@ -15,7 +15,7 @@
 // Generated with protocol_gen.go -- do not edit this file.
 //   go run scripts/protocol_gen/protocol_gen.go
 //
-// DAP version 1.41.0
+// DAP version 1.43.0
 
 #include "dap/protocol.h"
 
@@ -103,6 +103,7 @@
     DAP_FIELD(linesStartAt1, "linesStartAt1"),
     DAP_FIELD(locale, "locale"),
     DAP_FIELD(pathFormat, "pathFormat"),
+    DAP_FIELD(supportsInvalidatedEvent, "supportsInvalidatedEvent"),
     DAP_FIELD(supportsMemoryReferences, "supportsMemoryReferences"),
     DAP_FIELD(supportsProgressReporting, "supportsProgressReporting"),
     DAP_FIELD(supportsRunInTerminalRequest, "supportsRunInTerminalRequest"),
@@ -172,6 +173,7 @@
 DAP_IMPLEMENT_STRUCT_TYPEINFO(SetExceptionBreakpointsRequest,
                               "setExceptionBreakpoints",
                               DAP_FIELD(exceptionOptions, "exceptionOptions"),
+                              DAP_FIELD(filterOptions, "filterOptions"),
                               DAP_FIELD(filters, "filters"));
 
 DAP_IMPLEMENT_STRUCT_TYPEINFO(SetExpressionRequest,
diff --git a/src/protocol_response.cpp b/src/protocol_response.cpp
index 99a278f..f96c3cf 100644
--- a/src/protocol_response.cpp
+++ b/src/protocol_response.cpp
@@ -15,7 +15,7 @@
 // Generated with protocol_gen.go -- do not edit this file.
 //   go run scripts/protocol_gen/protocol_gen.go
 //
-// DAP version 1.41.0
+// DAP version 1.43.0
 
 #include "dap/protocol.h"
 
@@ -100,6 +100,7 @@
               "supportsDelayedStackTraceLoading"),
     DAP_FIELD(supportsDisassembleRequest, "supportsDisassembleRequest"),
     DAP_FIELD(supportsEvaluateForHovers, "supportsEvaluateForHovers"),
+    DAP_FIELD(supportsExceptionFilterOptions, "supportsExceptionFilterOptions"),
     DAP_FIELD(supportsExceptionInfoRequest, "supportsExceptionInfoRequest"),
     DAP_FIELD(supportsExceptionOptions, "supportsExceptionOptions"),
     DAP_FIELD(supportsFunctionBreakpoints, "supportsFunctionBreakpoints"),
diff --git a/src/protocol_types.cpp b/src/protocol_types.cpp
index 61047cd..a9e5355 100644
--- a/src/protocol_types.cpp
+++ b/src/protocol_types.cpp
@@ -15,7 +15,7 @@
 // Generated with protocol_gen.go -- do not edit this file.
 //   go run scripts/protocol_gen/protocol_gen.go
 //
-// DAP version 1.41.0
+// DAP version 1.43.0
 
 #include "dap/protocol.h"
 
@@ -72,7 +72,9 @@
                               "",
                               DAP_FIELD(def, "default"),
                               DAP_FIELD(filter, "filter"),
-                              DAP_FIELD(label, "label"));
+                              DAP_FIELD(label, "label"),
+                              DAP_FIELD(supportsCondition,
+                                        "supportsCondition"));
 
 DAP_IMPLEMENT_STRUCT_TYPEINFO(
     Capabilities,
@@ -95,6 +97,7 @@
               "supportsDelayedStackTraceLoading"),
     DAP_FIELD(supportsDisassembleRequest, "supportsDisassembleRequest"),
     DAP_FIELD(supportsEvaluateForHovers, "supportsEvaluateForHovers"),
+    DAP_FIELD(supportsExceptionFilterOptions, "supportsExceptionFilterOptions"),
     DAP_FIELD(supportsExceptionInfoRequest, "supportsExceptionInfoRequest"),
     DAP_FIELD(supportsExceptionOptions, "supportsExceptionOptions"),
     DAP_FIELD(supportsFunctionBreakpoints, "supportsFunctionBreakpoints"),
@@ -186,6 +189,8 @@
                               DAP_FIELD(label, "label"),
                               DAP_FIELD(line, "line"));
 
+DAP_IMPLEMENT_STRUCT_TYPEINFO(InvalidatedAreas, "");
+
 DAP_IMPLEMENT_STRUCT_TYPEINFO(Module,
                               "",
                               DAP_FIELD(addressRange, "addressRange"),
@@ -241,6 +246,11 @@
                               DAP_FIELD(breakMode, "breakMode"),
                               DAP_FIELD(path, "path"));
 
+DAP_IMPLEMENT_STRUCT_TYPEINFO(ExceptionFilterOptions,
+                              "",
+                              DAP_FIELD(condition, "condition"),
+                              DAP_FIELD(filterId, "filterId"));
+
 DAP_IMPLEMENT_STRUCT_TYPEINFO(FunctionBreakpoint,
                               "",
                               DAP_FIELD(condition, "condition"),
diff --git a/src/session.cpp b/src/session.cpp
index ad6597c..95b30a0 100644
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -335,7 +335,7 @@
     return [=] {
       handler(
           data,
-          [&](const dap::TypeInfo* typeinfo, const void* data) {
+          [=](const dap::TypeInfo* typeinfo, const void* data) {
             // onSuccess
             dap::json::Serializer s;
             s.object([&](dap::FieldSerializer* fs) {
@@ -354,7 +354,7 @@
               handler(data, nullptr);
             }
           },
-          [&](const dap::TypeInfo* typeinfo, const dap::Error& error) {
+          [=](const dap::TypeInfo* typeinfo, const dap::Error& error) {
             // onError
             dap::json::Serializer s;
             s.object([&](dap::FieldSerializer* fs) {
diff --git a/src/session_test.cpp b/src/session_test.cpp
index 21b73d6..eeb8fe3 100644
--- a/src/session_test.cpp
+++ b/src/session_test.cpp
@@ -269,6 +269,142 @@
   ASSERT_EQ(got.error.message, "Oh noes!");
 }
 
+TEST_F(SessionTest, RequestCallbackResponse) {
+  using ResponseCallback = std::function<void(dap::SetBreakpointsResponse)>;
+
+  server->registerHandler(
+      [&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
+        dap::SetBreakpointsResponse response;
+        dap::Breakpoint bp;
+        bp.line = 2;
+        response.breakpoints.emplace_back(std::move(bp));
+        callback(response);
+      });
+
+  bind();
+
+  auto got = client->send(dap::SetBreakpointsRequest{}).get();
+
+  // Check response was received correctly.
+  ASSERT_EQ(got.error, false);
+  ASSERT_EQ(got.response.breakpoints.size(), 1U);
+}
+
+TEST_F(SessionTest, RequestCallbackResponseOrError) {
+  using ResponseCallback =
+      std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
+
+  server->registerHandler(
+      [&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
+        dap::SetBreakpointsResponse response;
+        dap::Breakpoint bp;
+        bp.line = 2;
+        response.breakpoints.emplace_back(std::move(bp));
+        callback(response);
+      });
+
+  bind();
+
+  auto got = client->send(dap::SetBreakpointsRequest{}).get();
+
+  // Check response was received correctly.
+  ASSERT_EQ(got.error, false);
+  ASSERT_EQ(got.response.breakpoints.size(), 1U);
+}
+
+TEST_F(SessionTest, RequestCallbackError) {
+  using ResponseCallback =
+      std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
+
+  server->registerHandler(
+      [&](const dap::SetBreakpointsRequest&, const ResponseCallback& callback) {
+        callback(dap::Error("Oh noes!"));
+      });
+
+  bind();
+
+  auto got = client->send(dap::SetBreakpointsRequest{}).get();
+
+  // Check response was received correctly.
+  ASSERT_EQ(got.error, true);
+  ASSERT_EQ(got.error.message, "Oh noes!");
+}
+
+TEST_F(SessionTest, RequestCallbackSuccessAfterReturn) {
+  using ResponseCallback =
+      std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
+
+  ResponseCallback callback;
+  std::mutex mutex;
+  std::condition_variable cv;
+
+  server->registerHandler(
+      [&](const dap::SetBreakpointsRequest&, const ResponseCallback& cb) {
+        std::unique_lock<std::mutex> lock(mutex);
+        callback = cb;
+        cv.notify_all();
+      });
+
+  bind();
+
+  auto future = client->send(dap::SetBreakpointsRequest{});
+
+  {
+    dap::SetBreakpointsResponse response;
+    dap::Breakpoint bp;
+    bp.line = 2;
+    response.breakpoints.emplace_back(std::move(bp));
+
+    // Wait for the handler to be called.
+    std::unique_lock<std::mutex> lock(mutex);
+    cv.wait(lock, [&] { return static_cast<bool>(callback); });
+
+    // Issue the callback
+    callback(response);
+  }
+
+  auto got = future.get();
+
+  // Check response was received correctly.
+  ASSERT_EQ(got.error, false);
+  ASSERT_EQ(got.response.breakpoints.size(), 1U);
+}
+
+TEST_F(SessionTest, RequestCallbackErrorAfterReturn) {
+  using ResponseCallback =
+      std::function<void(dap::ResponseOrError<dap::SetBreakpointsResponse>)>;
+
+  ResponseCallback callback;
+  std::mutex mutex;
+  std::condition_variable cv;
+
+  server->registerHandler(
+      [&](const dap::SetBreakpointsRequest&, const ResponseCallback& cb) {
+        std::unique_lock<std::mutex> lock(mutex);
+        callback = cb;
+        cv.notify_all();
+      });
+
+  bind();
+
+  auto future = client->send(dap::SetBreakpointsRequest{});
+
+  {
+    // Wait for the handler to be called.
+    std::unique_lock<std::mutex> lock(mutex);
+    cv.wait(lock, [&] { return static_cast<bool>(callback); });
+
+    // Issue the callback
+    callback(dap::Error("Oh noes!"));
+  }
+
+  auto got = future.get();
+
+  // Check response was received correctly.
+  ASSERT_EQ(got.error, true);
+  ASSERT_EQ(got.error.message, "Oh noes!");
+}
+
 TEST_F(SessionTest, ResponseSentHandlerSuccess) {
   const auto response = createResponse();
 
diff --git a/src/traits_test.cpp b/src/traits_test.cpp
new file mode 100644
index 0000000..aafca04
--- /dev/null
+++ b/src/traits_test.cpp
@@ -0,0 +1,387 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "dap/traits.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace dap {
+namespace traits {
+
+namespace {
+struct S {};
+struct E : S {};
+void F1(S) {}
+void F3(int, S, float) {}
+void E1(E) {}
+void E3(int, E, float) {}
+}  // namespace
+
+TEST(ParameterType, Function) {
+  F1({});        // Avoid unused method warning
+  F3(0, {}, 0);  // Avoid unused method warning
+  static_assert(std::is_same<ParameterType<decltype(&F1), 0>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&F3), 0>, int>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&F3), 1>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&F3), 2>, float>::value,
+                "");
+}
+
+TEST(ParameterType, Method) {
+  class C {
+   public:
+    void F1(S) {}
+    void F3(int, S, float) {}
+  };
+  C().F1({});        // Avoid unused method warning
+  C().F3(0, {}, 0);  // Avoid unused method warning
+  static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
+                "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
+                "");
+}
+
+TEST(ParameterType, ConstMethod) {
+  class C {
+   public:
+    void F1(S) const {}
+    void F3(int, S, float) const {}
+  };
+  C().F1({});        // Avoid unused method warning
+  C().F3(0, {}, 0);  // Avoid unused method warning
+  static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
+                "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
+                "");
+}
+
+TEST(ParameterType, StaticMethod) {
+  class C {
+   public:
+    static void F1(S) {}
+    static void F3(int, S, float) {}
+  };
+  C::F1({});        // Avoid unused method warning
+  C::F3(0, {}, 0);  // Avoid unused method warning
+  static_assert(std::is_same<ParameterType<decltype(&C::F1), 0>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 0>, int>::value,
+                "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 1>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(&C::F3), 2>, float>::value,
+                "");
+}
+
+TEST(ParameterType, FunctionLike) {
+  using F1 = std::function<void(S)>;
+  using F3 = std::function<void(int, S, float)>;
+  static_assert(std::is_same<ParameterType<F1, 0>, S>::value, "");
+  static_assert(std::is_same<ParameterType<F3, 0>, int>::value, "");
+  static_assert(std::is_same<ParameterType<F3, 1>, S>::value, "");
+  static_assert(std::is_same<ParameterType<F3, 2>, float>::value, "");
+}
+
+TEST(ParameterType, Lambda) {
+  auto l1 = [](S) {};
+  auto l3 = [](int, S, float) {};
+  static_assert(std::is_same<ParameterType<decltype(l1), 0>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(l3), 0>, int>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(l3), 1>, S>::value, "");
+  static_assert(std::is_same<ParameterType<decltype(l3), 2>, float>::value, "");
+}
+
+TEST(HasSignature, Function) {
+  F1({});        // Avoid unused method warning
+  F3(0, {}, 0);  // Avoid unused method warning
+  static_assert(HasSignature<decltype(&F1), decltype(&F1)>::value, "");
+  static_assert(HasSignature<decltype(&F3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(&F3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(&F3), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(&F1), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(&F3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(&F3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(&F3), decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, Method) {
+  class C {
+   public:
+    void F1(S) {}
+    void F3(int, S, float) {}
+  };
+  C().F1({});        // Avoid unused method warning
+  C().F3(0, {}, 0);  // Avoid unused method warning
+
+  static_assert(HasSignature<decltype(&C::F1), decltype(&F1)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F1), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, ConstMethod) {
+  class C {
+   public:
+    void F1(S) const {}
+    void F3(int, S, float) const {}
+  };
+  C().F1({});        // Avoid unused method warning
+  C().F3(0, {}, 0);  // Avoid unused method warning
+
+  static_assert(HasSignature<decltype(&C::F1), decltype(&F1)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F1), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, StaticMethod) {
+  class C {
+   public:
+    static void F1(S) {}
+    static void F3(int, S, float) {}
+  };
+  C::F1({});        // Avoid unused method warning
+  C::F3(0, {}, 0);  // Avoid unused method warning
+
+  static_assert(HasSignature<decltype(&C::F1), decltype(&F1)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F1), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(&C::F3), decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, FunctionLike) {
+  using f1 = std::function<void(S)>;
+  using f3 = std::function<void(int, S, float)>;
+  static_assert(HasSignature<f1, decltype(&F1)>::value, "");
+  static_assert(HasSignature<f3, decltype(&F3)>::value, "");
+  static_assert(HasSignature<f3, decltype(&F3)>::value, "");
+  static_assert(HasSignature<f3, decltype(&F3)>::value, "");
+  static_assert(!HasSignature<f1, decltype(&F3)>::value, "");
+  static_assert(!HasSignature<f3, decltype(&F1)>::value, "");
+  static_assert(!HasSignature<f3, decltype(&F1)>::value, "");
+  static_assert(!HasSignature<f3, decltype(&F1)>::value, "");
+}
+
+TEST(HasSignature, Lambda) {
+  auto l1 = [](S) {};
+  auto l3 = [](int, S, float) {};
+  static_assert(HasSignature<decltype(l1), decltype(&F1)>::value, "");
+  static_assert(HasSignature<decltype(l3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(l3), decltype(&F3)>::value, "");
+  static_assert(HasSignature<decltype(l3), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(l1), decltype(&F3)>::value, "");
+  static_assert(!HasSignature<decltype(l3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(l3), decltype(&F1)>::value, "");
+  static_assert(!HasSignature<decltype(l3), decltype(&F1)>::value, "");
+}
+
+////
+
+TEST(CompatibleWith, Function) {
+  F1({});        // Avoid unused method warning
+  F3(0, {}, 0);  // Avoid unused method warning
+  E1({});        // Avoid unused method warning
+  E3(0, {}, 0);  // Avoid unused method warning
+  static_assert(CompatibleWith<decltype(&F1), decltype(&F1)>::value, "");
+  static_assert(CompatibleWith<decltype(&F3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&F3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&F3), decltype(&F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(&F1), decltype(&F3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&F3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&F3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&F3), decltype(&F1)>::value, "");
+
+  static_assert(CompatibleWith<decltype(&E1), decltype(&F1)>::value, "");
+  static_assert(CompatibleWith<decltype(&E3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&E3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&E3), decltype(&F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(&F1), decltype(&E1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&F3), decltype(&E3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&F3), decltype(&E3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&F3), decltype(&E3)>::value, "");
+}
+
+TEST(CompatibleWith, Method) {
+  class C {
+   public:
+    void F1(S) {}
+    void F3(int, S, float) {}
+    void E1(E) {}
+    void E3(int, E, float) {}
+  };
+  C().F1({});        // Avoid unused method warning
+  C().F3(0, {}, 0);  // Avoid unused method warning
+  C().E1({});        // Avoid unused method warning
+  C().E3(0, {}, 0);  // Avoid unused method warning
+
+  static_assert(CompatibleWith<decltype(&C::F1), decltype(&F1)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(&C::F1), decltype(&F3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+
+  static_assert(CompatibleWith<decltype(&C::E1), decltype(&C::F1)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(&C::F1), decltype(&C::E1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+}
+
+TEST(CompatibleWith, ConstMethod) {
+  class C {
+   public:
+    void F1(S) const {}
+    void F3(int, S, float) const {}
+    void E1(E) const {}
+    void E3(int, E, float) const {}
+  };
+  C().F1({});        // Avoid unused method warning
+  C().F3(0, {}, 0);  // Avoid unused method warning
+  C().E1({});        // Avoid unused method warning
+  C().E3(0, {}, 0);  // Avoid unused method warning
+
+  static_assert(CompatibleWith<decltype(&C::F1), decltype(&F1)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(&C::F1), decltype(&F3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+
+  static_assert(CompatibleWith<decltype(&C::E1), decltype(&C::F1)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(&C::F1), decltype(&C::E1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+}
+
+TEST(CompatibleWith, StaticMethod) {
+  class C {
+   public:
+    static void F1(S) {}
+    static void F3(int, S, float) {}
+    static void E1(E) {}
+    static void E3(int, E, float) {}
+  };
+  C::F1({});        // Avoid unused method warning
+  C::F3(0, {}, 0);  // Avoid unused method warning
+  C::E1({});        // Avoid unused method warning
+  C::E3(0, {}, 0);  // Avoid unused method warning
+
+  static_assert(CompatibleWith<decltype(&C::F1), decltype(&F1)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::F3), decltype(&F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(&C::F1), decltype(&F3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&F1)>::value, "");
+
+  static_assert(CompatibleWith<decltype(&C::E1), decltype(&C::F1)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+  static_assert(CompatibleWith<decltype(&C::E3), decltype(&C::F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(&C::F1), decltype(&C::E1)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+  static_assert(!CompatibleWith<decltype(&C::F3), decltype(&C::E3)>::value, "");
+}
+
+TEST(CompatibleWith, FunctionLike) {
+  using f1 = std::function<void(S)>;
+  using f3 = std::function<void(int, S, float)>;
+  using e1 = std::function<void(E)>;
+  using e3 = std::function<void(int, E, float)>;
+  static_assert(CompatibleWith<f1, decltype(&F1)>::value, "");
+  static_assert(CompatibleWith<f3, decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<f3, decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<f3, decltype(&F3)>::value, "");
+
+  static_assert(!CompatibleWith<f1, decltype(&F3)>::value, "");
+  static_assert(!CompatibleWith<f3, decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<f3, decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<f3, decltype(&F1)>::value, "");
+
+  static_assert(CompatibleWith<e1, f1>::value, "");
+  static_assert(CompatibleWith<e3, f3>::value, "");
+  static_assert(CompatibleWith<e3, f3>::value, "");
+  static_assert(CompatibleWith<e3, f3>::value, "");
+
+  static_assert(!CompatibleWith<f1, e1>::value, "");
+  static_assert(!CompatibleWith<f3, e3>::value, "");
+  static_assert(!CompatibleWith<f3, e3>::value, "");
+  static_assert(!CompatibleWith<f3, e3>::value, "");
+}
+
+TEST(CompatibleWith, Lambda) {
+  auto f1 = [](S) {};
+  auto f3 = [](int, S, float) {};
+  auto e1 = [](E) {};
+  auto e3 = [](int, E, float) {};
+  static_assert(CompatibleWith<decltype(f1), decltype(&F1)>::value, "");
+  static_assert(CompatibleWith<decltype(f3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(f3), decltype(&F3)>::value, "");
+  static_assert(CompatibleWith<decltype(f3), decltype(&F3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(f1), decltype(&F3)>::value, "");
+  static_assert(!CompatibleWith<decltype(f3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(f3), decltype(&F1)>::value, "");
+  static_assert(!CompatibleWith<decltype(f3), decltype(&F1)>::value, "");
+
+  static_assert(CompatibleWith<decltype(e1), decltype(f1)>::value, "");
+  static_assert(CompatibleWith<decltype(e3), decltype(f3)>::value, "");
+  static_assert(CompatibleWith<decltype(e3), decltype(f3)>::value, "");
+  static_assert(CompatibleWith<decltype(e3), decltype(f3)>::value, "");
+
+  static_assert(!CompatibleWith<decltype(f1), decltype(e1)>::value, "");
+  static_assert(!CompatibleWith<decltype(f3), decltype(e3)>::value, "");
+  static_assert(!CompatibleWith<decltype(f3), decltype(e3)>::value, "");
+  static_assert(!CompatibleWith<decltype(f3), decltype(e3)>::value, "");
+}
+
+}  // namespace traits
+}  // namespace dap