mirror of
https://github.com/Kitware/CMake.git
synced 2026-04-22 22:31:18 -05:00
Merge branch 'upstream-cppdap' into import-cppdap
* upstream-cppdap: cppdap 2023-05-26 (03cc1867)
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
// Copyright 2019 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_any_h
|
||||
#define dap_any_h
|
||||
|
||||
#include "typeinfo.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace dap {
|
||||
|
||||
template <typename T>
|
||||
struct TypeOf;
|
||||
class Deserializer;
|
||||
class Serializer;
|
||||
|
||||
// any provides a type-safe container for values of any of dap type (boolean,
|
||||
// integer, number, array, variant, any, null, dap-structs).
|
||||
class any {
|
||||
public:
|
||||
// constructors
|
||||
inline any() = default;
|
||||
inline any(const any& other) noexcept;
|
||||
inline any(any&& other) noexcept;
|
||||
|
||||
template <typename T>
|
||||
inline any(const T& val);
|
||||
|
||||
// destructors
|
||||
inline ~any();
|
||||
|
||||
// replaces the contained value with a null.
|
||||
inline void reset();
|
||||
|
||||
// assignment
|
||||
inline any& operator=(const any& rhs);
|
||||
inline any& operator=(any&& rhs) noexcept;
|
||||
template <typename T>
|
||||
inline any& operator=(const T& val);
|
||||
inline any& operator=(const std::nullptr_t& val);
|
||||
|
||||
// get() returns the contained value of the type T.
|
||||
// If the any does not contain a value of type T, then get() will assert.
|
||||
template <typename T>
|
||||
inline T& get() const;
|
||||
|
||||
// is() returns true iff the contained value is of type T.
|
||||
template <typename T>
|
||||
inline bool is() const;
|
||||
|
||||
private:
|
||||
friend class Deserializer;
|
||||
friend class Serializer;
|
||||
|
||||
static inline void* alignUp(void* val, size_t alignment);
|
||||
inline void alloc(size_t size, size_t align);
|
||||
inline void free();
|
||||
inline bool isInBuffer(void* ptr) const;
|
||||
|
||||
void* value = nullptr;
|
||||
const TypeInfo* type = nullptr;
|
||||
void* heap = nullptr; // heap allocation
|
||||
uint8_t buffer[32]; // or internal allocation
|
||||
};
|
||||
|
||||
inline any::~any() {
|
||||
reset();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline any::any(const T& val) {
|
||||
*this = val;
|
||||
}
|
||||
|
||||
any::any(const any& other) noexcept : type(other.type) {
|
||||
if (other.value != nullptr) {
|
||||
alloc(type->size(), type->alignment());
|
||||
type->copyConstruct(value, other.value);
|
||||
}
|
||||
}
|
||||
|
||||
any::any(any&& other) noexcept : type(other.type) {
|
||||
if (other.isInBuffer(other.value)) {
|
||||
alloc(type->size(), type->alignment());
|
||||
type->copyConstruct(value, other.value);
|
||||
} else {
|
||||
value = other.value;
|
||||
}
|
||||
other.value = nullptr;
|
||||
other.type = nullptr;
|
||||
}
|
||||
|
||||
void any::reset() {
|
||||
if (value != nullptr) {
|
||||
type->destruct(value);
|
||||
free();
|
||||
}
|
||||
value = nullptr;
|
||||
type = nullptr;
|
||||
}
|
||||
|
||||
any& any::operator=(const any& rhs) {
|
||||
reset();
|
||||
type = rhs.type;
|
||||
if (rhs.value != nullptr) {
|
||||
alloc(type->size(), type->alignment());
|
||||
type->copyConstruct(value, rhs.value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
any& any::operator=(any&& rhs) noexcept {
|
||||
reset();
|
||||
type = rhs.type;
|
||||
if (rhs.isInBuffer(rhs.value)) {
|
||||
alloc(type->size(), type->alignment());
|
||||
type->copyConstruct(value, rhs.value);
|
||||
} else {
|
||||
value = rhs.value;
|
||||
}
|
||||
rhs.value = nullptr;
|
||||
rhs.type = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
any& any::operator=(const T& val) {
|
||||
if (!is<T>()) {
|
||||
reset();
|
||||
type = TypeOf<T>::type();
|
||||
alloc(type->size(), type->alignment());
|
||||
type->copyConstruct(value, &val);
|
||||
} else {
|
||||
#ifdef __clang_analyzer__
|
||||
assert(value != nullptr);
|
||||
#endif
|
||||
*reinterpret_cast<T*>(value) = val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
any& any::operator=(const std::nullptr_t&) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& any::get() const {
|
||||
static_assert(!std::is_same<T, std::nullptr_t>(),
|
||||
"Cannot get nullptr from 'any'.");
|
||||
assert(is<T>());
|
||||
return *reinterpret_cast<T*>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool any::is() const {
|
||||
return type == TypeOf<T>::type();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool any::is<std::nullptr_t>() const {
|
||||
return value == nullptr;
|
||||
}
|
||||
|
||||
void* any::alignUp(void* val, size_t alignment) {
|
||||
auto ptr = reinterpret_cast<uintptr_t>(val);
|
||||
return reinterpret_cast<void*>(alignment *
|
||||
((ptr + alignment - 1) / alignment));
|
||||
}
|
||||
|
||||
void any::alloc(size_t size, size_t align) {
|
||||
assert(value == nullptr);
|
||||
value = alignUp(buffer, align);
|
||||
if (isInBuffer(reinterpret_cast<uint8_t*>(value) + size - 1)) {
|
||||
return;
|
||||
}
|
||||
heap = new uint8_t[size + align];
|
||||
value = alignUp(heap, align);
|
||||
}
|
||||
|
||||
void any::free() {
|
||||
assert(value != nullptr);
|
||||
if (heap != nullptr) {
|
||||
delete[] reinterpret_cast<uint8_t*>(heap);
|
||||
heap = nullptr;
|
||||
}
|
||||
value = nullptr;
|
||||
}
|
||||
|
||||
bool any::isInBuffer(void* ptr) const {
|
||||
auto addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
return addr >= reinterpret_cast<uintptr_t>(buffer) &&
|
||||
addr < reinterpret_cast<uintptr_t>(buffer + sizeof(buffer));
|
||||
}
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_any_h
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2020 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_dap_h
|
||||
#define dap_dap_h
|
||||
|
||||
namespace dap {
|
||||
|
||||
// Explicit library initialization and termination functions.
|
||||
//
|
||||
// cppdap automatically initializes and terminates its internal state using lazy
|
||||
// static initialization, and so will usually work fine without explicit calls
|
||||
// to these functions.
|
||||
// However, if you use cppdap types in global state, you may need to call these
|
||||
// functions to ensure that cppdap is not uninitialized before the last usage.
|
||||
//
|
||||
// Each call to initialize() must have a corresponding call to terminate().
|
||||
// It is undefined behaviour to call initialize() after terminate().
|
||||
void initialize();
|
||||
void terminate();
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_dap_h
|
||||
@@ -0,0 +1,179 @@
|
||||
// Copyright 2019 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_future_h
|
||||
#define dap_future_h
|
||||
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace dap {
|
||||
|
||||
// internal functionality
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct promise_state {
|
||||
T val;
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
bool hasVal = false;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// forward declaration
|
||||
template <typename T>
|
||||
class promise;
|
||||
|
||||
// future_status is the enumeration returned by future::wait_for and
|
||||
// future::wait_until.
|
||||
enum class future_status {
|
||||
ready,
|
||||
timeout,
|
||||
};
|
||||
|
||||
// future is a minimal reimplementation of std::future, that does not suffer
|
||||
// from TSAN false positives. See:
|
||||
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=69204
|
||||
template <typename T>
|
||||
class future {
|
||||
public:
|
||||
using State = detail::promise_state<T>;
|
||||
|
||||
// constructors
|
||||
inline future() = default;
|
||||
inline future(future&&) = default;
|
||||
|
||||
// valid() returns true if the future has an internal state.
|
||||
bool valid() const;
|
||||
|
||||
// get() blocks until the future has a valid result, and returns it.
|
||||
// The future must have a valid internal state to call this method.
|
||||
inline T get();
|
||||
|
||||
// wait() blocks until the future has a valid result.
|
||||
// The future must have a valid internal state to call this method.
|
||||
void wait() const;
|
||||
|
||||
// wait_for() blocks until the future has a valid result, or the timeout is
|
||||
// reached.
|
||||
// The future must have a valid internal state to call this method.
|
||||
template <class Rep, class Period>
|
||||
future_status wait_for(
|
||||
const std::chrono::duration<Rep, Period>& timeout) const;
|
||||
|
||||
// wait_until() blocks until the future has a valid result, or the timeout is
|
||||
// reached.
|
||||
// The future must have a valid internal state to call this method.
|
||||
template <class Clock, class Duration>
|
||||
future_status wait_until(
|
||||
const std::chrono::time_point<Clock, Duration>& timeout) const;
|
||||
|
||||
private:
|
||||
friend promise<T>;
|
||||
future(const future&) = delete;
|
||||
inline future(const std::shared_ptr<State>& state);
|
||||
|
||||
std::shared_ptr<State> state = std::make_shared<State>();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
future<T>::future(const std::shared_ptr<State>& s) : state(s) {}
|
||||
|
||||
template <typename T>
|
||||
bool future<T>::valid() const {
|
||||
return static_cast<bool>(state);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T future<T>::get() {
|
||||
std::unique_lock<std::mutex> lock(state->mutex);
|
||||
state->cv.wait(lock, [&] { return state->hasVal; });
|
||||
return state->val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void future<T>::wait() const {
|
||||
std::unique_lock<std::mutex> lock(state->mutex);
|
||||
state->cv.wait(lock, [&] { return state->hasVal; });
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <class Rep, class Period>
|
||||
future_status future<T>::wait_for(
|
||||
const std::chrono::duration<Rep, Period>& timeout) const {
|
||||
std::unique_lock<std::mutex> lock(state->mutex);
|
||||
return state->cv.wait_for(lock, timeout, [&] { return state->hasVal; })
|
||||
? future_status::ready
|
||||
: future_status::timeout;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <class Clock, class Duration>
|
||||
future_status future<T>::wait_until(
|
||||
const std::chrono::time_point<Clock, Duration>& timeout) const {
|
||||
std::unique_lock<std::mutex> lock(state->mutex);
|
||||
return state->cv.wait_until(lock, timeout, [&] { return state->hasVal; })
|
||||
? future_status::ready
|
||||
: future_status::timeout;
|
||||
}
|
||||
|
||||
// promise is a minimal reimplementation of std::promise, that does not suffer
|
||||
// from TSAN false positives. See:
|
||||
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=69204
|
||||
template <typename T>
|
||||
class promise {
|
||||
public:
|
||||
// constructors
|
||||
inline promise() = default;
|
||||
inline promise(promise&& other) = default;
|
||||
inline promise(const promise& other) = default;
|
||||
|
||||
// set_value() stores value to the shared state.
|
||||
// set_value() must only be called once.
|
||||
inline void set_value(const T& value) const;
|
||||
inline void set_value(T&& value) const;
|
||||
|
||||
// get_future() returns a future sharing this promise's state.
|
||||
future<T> get_future();
|
||||
|
||||
private:
|
||||
using State = detail::promise_state<T>;
|
||||
std::shared_ptr<State> state = std::make_shared<State>();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
future<T> promise<T>::get_future() {
|
||||
return future<T>(state);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void promise<T>::set_value(const T& value) const {
|
||||
std::unique_lock<std::mutex> lock(state->mutex);
|
||||
state->val = value;
|
||||
state->hasVal = true;
|
||||
state->cv.notify_all();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void promise<T>::set_value(T&& value) const {
|
||||
std::unique_lock<std::mutex> lock(state->mutex);
|
||||
state->val = std::move(value);
|
||||
state->hasVal = true;
|
||||
state->cv.notify_all();
|
||||
}
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_future_h
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2019 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_io_h
|
||||
#define dap_io_h
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdio.h> // FILE
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <utility> // std::pair
|
||||
|
||||
namespace dap {
|
||||
|
||||
class Closable {
|
||||
public:
|
||||
virtual ~Closable() = default;
|
||||
|
||||
// isOpen() returns true if the stream has not been closed.
|
||||
virtual bool isOpen() = 0;
|
||||
|
||||
// close() closes the stream.
|
||||
virtual void close() = 0;
|
||||
};
|
||||
|
||||
// Reader is an interface for reading from a byte stream.
|
||||
class Reader : virtual public Closable {
|
||||
public:
|
||||
// read() attempts to read at most n bytes into buffer, returning the number
|
||||
// of bytes read.
|
||||
// read() will block until the stream is closed or at least one byte is read.
|
||||
virtual size_t read(void* buffer, size_t n) = 0;
|
||||
};
|
||||
|
||||
// Writer is an interface for writing to a byte stream.
|
||||
class Writer : virtual public Closable {
|
||||
public:
|
||||
// write() writes n bytes from buffer into the stream.
|
||||
// Returns true on success, or false if there was an error or the stream was
|
||||
// closed.
|
||||
virtual bool write(const void* buffer, size_t n) = 0;
|
||||
};
|
||||
|
||||
// ReaderWriter is an interface that combines the Reader and Writer interfaces.
|
||||
class ReaderWriter : public Reader, public Writer {
|
||||
public:
|
||||
// create() returns a ReaderWriter that delegates the interface methods on to
|
||||
// the provided Reader and Writer.
|
||||
// isOpen() returns true if the Reader and Writer both return true for
|
||||
// isOpen().
|
||||
// close() closes both the Reader and Writer.
|
||||
static std::shared_ptr<ReaderWriter> create(const std::shared_ptr<Reader>&,
|
||||
const std::shared_ptr<Writer>&);
|
||||
};
|
||||
|
||||
// pipe() returns a ReaderWriter where the Writer streams to the Reader.
|
||||
// Writes are internally buffered.
|
||||
// Calling close() on either the Reader or Writer will close both ends of the
|
||||
// stream.
|
||||
std::shared_ptr<ReaderWriter> pipe();
|
||||
|
||||
// file() wraps file with a ReaderWriter.
|
||||
// If closable is false, then a call to ReaderWriter::close() will not close the
|
||||
// underlying file.
|
||||
std::shared_ptr<ReaderWriter> file(FILE* file, bool closable = true);
|
||||
|
||||
// file() opens (or creates) the file with the given path.
|
||||
std::shared_ptr<ReaderWriter> file(const char* path);
|
||||
|
||||
// spy() returns a Reader that copies all reads from the Reader r to the Writer
|
||||
// s, using the given optional prefix.
|
||||
std::shared_ptr<Reader> spy(const std::shared_ptr<Reader>& r,
|
||||
const std::shared_ptr<Writer>& s,
|
||||
const char* prefix = "\n->");
|
||||
|
||||
// spy() returns a Writer that copies all writes to the Writer w to the Writer
|
||||
// s, using the given optional prefix.
|
||||
std::shared_ptr<Writer> spy(const std::shared_ptr<Writer>& w,
|
||||
const std::shared_ptr<Writer>& s,
|
||||
const char* prefix = "\n<-");
|
||||
|
||||
// writef writes the printf style string to the writer w.
|
||||
bool writef(const std::shared_ptr<Writer>& w, const char* msg, ...);
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_io_h
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2019 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_network_h
|
||||
#define dap_network_h
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace dap {
|
||||
class ReaderWriter;
|
||||
|
||||
namespace net {
|
||||
|
||||
// connect() connects to the given TCP address and port.
|
||||
// If timeoutMillis is non-zero and no connection was made before timeoutMillis
|
||||
// milliseconds, then nullptr is returned.
|
||||
std::shared_ptr<ReaderWriter> connect(const char* addr,
|
||||
int port,
|
||||
uint32_t timeoutMillis = 0);
|
||||
|
||||
// Server implements a basic TCP server.
|
||||
class Server {
|
||||
// ignoreErrors() matches the OnError signature, and does nothing.
|
||||
static inline void ignoreErrors(const char*) {}
|
||||
|
||||
public:
|
||||
using OnError = std::function<void(const char*)>;
|
||||
using OnConnect = std::function<void(const std::shared_ptr<ReaderWriter>&)>;
|
||||
|
||||
virtual ~Server() = default;
|
||||
|
||||
// create() constructs and returns a new Server.
|
||||
static std::unique_ptr<Server> create();
|
||||
|
||||
// start() begins listening for connections on the given port.
|
||||
// callback will be called for each connection.
|
||||
// onError will be called for any connection errors.
|
||||
virtual bool start(int port,
|
||||
const OnConnect& callback,
|
||||
const OnError& onError = ignoreErrors) = 0;
|
||||
|
||||
// stop() stops listening for connections.
|
||||
// stop() is implicitly called on destruction.
|
||||
virtual void stop() = 0;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_network_h
|
||||
@@ -0,0 +1,263 @@
|
||||
// Copyright 2019 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_optional_h
|
||||
#define dap_optional_h
|
||||
|
||||
#include <assert.h>
|
||||
#include <type_traits>
|
||||
#include <utility> // std::move, std::forward
|
||||
|
||||
namespace dap {
|
||||
|
||||
// optional holds an 'optional' contained value.
|
||||
// This is similar to C++17's std::optional.
|
||||
template <typename T>
|
||||
class optional {
|
||||
template <typename U>
|
||||
using IsConvertibleToT =
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type;
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
// constructors
|
||||
inline optional() = default;
|
||||
inline optional(const optional& other);
|
||||
inline optional(optional&& other);
|
||||
template <typename U>
|
||||
inline optional(const optional<U>& other);
|
||||
template <typename U>
|
||||
inline optional(optional<U>&& other);
|
||||
template <typename U = value_type, typename = IsConvertibleToT<U>>
|
||||
inline optional(U&& value);
|
||||
|
||||
// value() returns the contained value.
|
||||
// If the optional does not contain a value, then value() will assert.
|
||||
inline T& value();
|
||||
inline const T& value() const;
|
||||
|
||||
// value() returns the contained value, or defaultValue if the optional does
|
||||
// not contain a value.
|
||||
inline const T& value(const T& defaultValue) const;
|
||||
|
||||
// operator bool() returns true if the optional contains a value.
|
||||
inline explicit operator bool() const noexcept;
|
||||
|
||||
// has_value() returns true if the optional contains a value.
|
||||
inline bool has_value() const;
|
||||
|
||||
// assignment
|
||||
inline optional& operator=(const optional& other);
|
||||
inline optional& operator=(optional&& other) noexcept;
|
||||
template <typename U = T, typename = IsConvertibleToT<U>>
|
||||
inline optional& operator=(U&& value);
|
||||
template <typename U>
|
||||
inline optional& operator=(const optional<U>& other);
|
||||
template <typename U>
|
||||
inline optional& operator=(optional<U>&& other);
|
||||
|
||||
// value access
|
||||
inline const T* operator->() const;
|
||||
inline T* operator->();
|
||||
inline const T& operator*() const;
|
||||
inline T& operator*();
|
||||
|
||||
private:
|
||||
T val{};
|
||||
bool set = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
optional<T>::optional(const optional& other) : val(other.val), set(other.set) {}
|
||||
|
||||
template <typename T>
|
||||
optional<T>::optional(optional&& other)
|
||||
: val(std::move(other.val)), set(other.set) {}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
optional<T>::optional(const optional<U>& other) : set(other.has_value()) {
|
||||
if (set) {
|
||||
val = static_cast<T>(other.value());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
optional<T>::optional(optional<U>&& other) : set(other.has_value()) {
|
||||
if (set) {
|
||||
val = static_cast<T>(std::move(other.value()));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U /*= T*/, typename>
|
||||
optional<T>::optional(U&& value) : val(std::forward<U>(value)), set(true) {}
|
||||
|
||||
template <typename T>
|
||||
T& optional<T>::value() {
|
||||
assert(set);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& optional<T>::value() const {
|
||||
assert(set);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& optional<T>::value(const T& defaultValue) const {
|
||||
if (!has_value()) {
|
||||
return defaultValue;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
optional<T>::operator bool() const noexcept {
|
||||
return set;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool optional<T>::has_value() const {
|
||||
return set;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
optional<T>& optional<T>::operator=(const optional& other) {
|
||||
val = other.val;
|
||||
set = other.set;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
optional<T>& optional<T>::operator=(optional&& other) noexcept {
|
||||
val = std::move(other.val);
|
||||
set = other.set;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U /* = T */, typename>
|
||||
optional<T>& optional<T>::operator=(U&& value) {
|
||||
val = std::forward<U>(value);
|
||||
set = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
optional<T>& optional<T>::operator=(const optional<U>& other) {
|
||||
val = other.val;
|
||||
set = other.set;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
optional<T>& optional<T>::operator=(optional<U>&& other) {
|
||||
val = std::move(other.val);
|
||||
set = other.set;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* optional<T>::operator->() const {
|
||||
assert(set);
|
||||
return &val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* optional<T>::operator->() {
|
||||
assert(set);
|
||||
return &val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& optional<T>::operator*() const {
|
||||
assert(set);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& optional<T>::operator*() {
|
||||
assert(set);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
|
||||
if (!lhs.has_value() && !rhs.has_value()) {
|
||||
return true;
|
||||
}
|
||||
if (!lhs.has_value() || !rhs.has_value()) {
|
||||
return false;
|
||||
}
|
||||
return lhs.value() == rhs.value();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator<(const optional<T>& lhs, const optional<U>& rhs) {
|
||||
if (!rhs.has_value()) {
|
||||
return false;
|
||||
}
|
||||
if (!lhs.has_value()) {
|
||||
return true;
|
||||
}
|
||||
return lhs.value() < rhs.value();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator<=(const optional<T>& lhs, const optional<U>& rhs) {
|
||||
if (!lhs.has_value()) {
|
||||
return true;
|
||||
}
|
||||
if (!rhs.has_value()) {
|
||||
return false;
|
||||
}
|
||||
return lhs.value() <= rhs.value();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator>(const optional<T>& lhs, const optional<U>& rhs) {
|
||||
if (!lhs.has_value()) {
|
||||
return false;
|
||||
}
|
||||
if (!rhs.has_value()) {
|
||||
return true;
|
||||
}
|
||||
return lhs.value() > rhs.value();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline bool operator>=(const optional<T>& lhs, const optional<U>& rhs) {
|
||||
if (!rhs.has_value()) {
|
||||
return true;
|
||||
}
|
||||
if (!lhs.has_value()) {
|
||||
return false;
|
||||
}
|
||||
return lhs.value() >= rhs.value();
|
||||
}
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_optional_h
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,253 @@
|
||||
// Copyright 2019 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_serialization_h
|
||||
#define dap_serialization_h
|
||||
|
||||
#include "typeof.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <cstddef> // ptrdiff_t
|
||||
#include <type_traits>
|
||||
|
||||
namespace dap {
|
||||
|
||||
// Field describes a single field of a struct.
|
||||
struct Field {
|
||||
std::string name; // name of the field
|
||||
ptrdiff_t offset; // offset of the field to the base of the struct
|
||||
const TypeInfo* type; // type of the field
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Deserializer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Deserializer is the interface used to decode data from structured storage.
|
||||
// Methods that return a bool use this to indicate success.
|
||||
class Deserializer {
|
||||
public:
|
||||
virtual ~Deserializer() = default;
|
||||
|
||||
// deserialization methods for simple data types.
|
||||
// If the stored object is not of the correct type, then these function will
|
||||
// return false.
|
||||
virtual bool deserialize(boolean*) const = 0;
|
||||
virtual bool deserialize(integer*) const = 0;
|
||||
virtual bool deserialize(number*) const = 0;
|
||||
virtual bool deserialize(string*) const = 0;
|
||||
virtual bool deserialize(object*) const = 0;
|
||||
virtual bool deserialize(any*) const = 0;
|
||||
|
||||
// count() returns the number of elements in the array object referenced by
|
||||
// this Deserializer.
|
||||
virtual size_t count() const = 0;
|
||||
|
||||
// array() calls the provided std::function for deserializing each array
|
||||
// element in the array object referenced by this Deserializer.
|
||||
virtual bool array(const std::function<bool(Deserializer*)>&) const = 0;
|
||||
|
||||
// field() calls the provided std::function for deserializing the field with
|
||||
// the given name from the struct object referenced by this Deserializer.
|
||||
virtual bool field(const std::string& name,
|
||||
const std::function<bool(Deserializer*)>&) const = 0;
|
||||
|
||||
// deserialize() delegates to TypeOf<T>::type()->deserialize().
|
||||
template <typename T,
|
||||
typename = std::enable_if<TypeOf<T>::has_custom_serialization>>
|
||||
inline bool deserialize(T*) const;
|
||||
|
||||
// deserialize() decodes an array.
|
||||
template <typename T>
|
||||
inline bool deserialize(dap::array<T>*) const;
|
||||
|
||||
// deserialize() decodes an optional.
|
||||
template <typename T>
|
||||
inline bool deserialize(dap::optional<T>*) const;
|
||||
|
||||
// deserialize() decodes an variant.
|
||||
template <typename T0, typename... Types>
|
||||
inline bool deserialize(dap::variant<T0, Types...>*) const;
|
||||
|
||||
// deserialize() decodes the struct field f with the given name.
|
||||
template <typename T>
|
||||
inline bool field(const std::string& name, T* f) const;
|
||||
};
|
||||
|
||||
template <typename T, typename>
|
||||
bool Deserializer::deserialize(T* ptr) const {
|
||||
return TypeOf<T>::type()->deserialize(this, ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Deserializer::deserialize(dap::array<T>* vec) const {
|
||||
auto n = count();
|
||||
vec->resize(n);
|
||||
size_t i = 0;
|
||||
if (!array([&](Deserializer* d) { return d->deserialize(&(*vec)[i++]); })) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Deserializer::deserialize(dap::optional<T>* opt) const {
|
||||
T v;
|
||||
if (deserialize(&v)) {
|
||||
*opt = v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
bool Deserializer::deserialize(dap::variant<T0, Types...>* var) const {
|
||||
return deserialize(&var->value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Deserializer::field(const std::string& name, T* v) const {
|
||||
return this->field(name,
|
||||
[&](const Deserializer* d) { return d->deserialize(v); });
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Serializer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class FieldSerializer;
|
||||
|
||||
// Serializer is the interface used to encode data to structured storage.
|
||||
// A Serializer is associated with a single storage object, whos type and value
|
||||
// is assigned by a call to serialize().
|
||||
// If serialize() is called multiple times on the same Serializer instance,
|
||||
// the last type and value is stored.
|
||||
// Methods that return a bool use this to indicate success.
|
||||
class Serializer {
|
||||
public:
|
||||
virtual ~Serializer() = default;
|
||||
|
||||
// serialization methods for simple data types.
|
||||
virtual bool serialize(boolean) = 0;
|
||||
virtual bool serialize(integer) = 0;
|
||||
virtual bool serialize(number) = 0;
|
||||
virtual bool serialize(const string&) = 0;
|
||||
virtual bool serialize(const dap::object&) = 0;
|
||||
virtual bool serialize(const any&) = 0;
|
||||
|
||||
// array() encodes count array elements to the array object referenced by this
|
||||
// Serializer. The std::function will be called count times, each time with a
|
||||
// Serializer that should be used to encode the n'th array element's data.
|
||||
virtual bool array(size_t count, const std::function<bool(Serializer*)>&) = 0;
|
||||
|
||||
// object() begins encoding the object referenced by this Serializer.
|
||||
// The std::function will be called with a FieldSerializer to serialize the
|
||||
// object's fields.
|
||||
virtual bool object(const std::function<bool(dap::FieldSerializer*)>&) = 0;
|
||||
|
||||
// remove() deletes the object referenced by this Serializer.
|
||||
// remove() can be used to serialize optionals with no value assigned.
|
||||
virtual void remove() = 0;
|
||||
|
||||
// serialize() delegates to TypeOf<T>::type()->serialize().
|
||||
template <typename T,
|
||||
typename = std::enable_if<TypeOf<T>::has_custom_serialization>>
|
||||
inline bool serialize(const T&);
|
||||
|
||||
// serialize() encodes the given array.
|
||||
template <typename T>
|
||||
inline bool serialize(const dap::array<T>&);
|
||||
|
||||
// serialize() encodes the given optional.
|
||||
template <typename T>
|
||||
inline bool serialize(const dap::optional<T>& v);
|
||||
|
||||
// serialize() encodes the given variant.
|
||||
template <typename T0, typename... Types>
|
||||
inline bool serialize(const dap::variant<T0, Types...>&);
|
||||
|
||||
// deserialize() encodes the given string.
|
||||
inline bool serialize(const char* v);
|
||||
protected:
|
||||
static inline const TypeInfo* get_any_type(const any&);
|
||||
static inline const void* get_any_val(const any&);
|
||||
};
|
||||
|
||||
inline const TypeInfo* Serializer::get_any_type(const any& a){
|
||||
return a.type;
|
||||
}
|
||||
const void* Serializer::get_any_val(const any& a) {
|
||||
return a.value;
|
||||
}
|
||||
|
||||
template <typename T, typename>
|
||||
bool Serializer::serialize(const T& object) {
|
||||
return TypeOf<T>::type()->serialize(this, &object);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Serializer::serialize(const dap::array<T>& vec) {
|
||||
auto it = vec.begin();
|
||||
return array(vec.size(), [&](Serializer* s) { return s->serialize(*it++); });
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Serializer::serialize(const dap::optional<T>& opt) {
|
||||
if (!opt.has_value()) {
|
||||
remove();
|
||||
return true;
|
||||
}
|
||||
return serialize(opt.value());
|
||||
}
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
bool Serializer::serialize(const dap::variant<T0, Types...>& var) {
|
||||
return serialize(var.value);
|
||||
}
|
||||
|
||||
bool Serializer::serialize(const char* v) {
|
||||
return serialize(std::string(v));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// FieldSerializer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FieldSerializer is the interface used to serialize fields of an object.
|
||||
class FieldSerializer {
|
||||
public:
|
||||
using SerializeFunc = std::function<bool(Serializer*)>;
|
||||
template <typename T>
|
||||
using IsSerializeFunc = std::is_convertible<T, SerializeFunc>;
|
||||
|
||||
virtual ~FieldSerializer() = default;
|
||||
|
||||
// field() encodes a field to the struct object referenced by this Serializer.
|
||||
// The SerializeFunc will be called with a Serializer used to encode the
|
||||
// field's data.
|
||||
virtual bool field(const std::string& name, const SerializeFunc&) = 0;
|
||||
|
||||
// field() encodes the field with the given name and value.
|
||||
template <
|
||||
typename T,
|
||||
typename = typename std::enable_if<!IsSerializeFunc<T>::value>::type>
|
||||
inline bool field(const std::string& name, const T& v);
|
||||
};
|
||||
|
||||
template <typename T, typename>
|
||||
bool FieldSerializer::field(const std::string& name, const T& v) {
|
||||
return this->field(name, [&](Serializer* s) { return s->serialize(v); });
|
||||
}
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_serialization_h
|
||||
@@ -0,0 +1,449 @@
|
||||
// Copyright 2019 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_session_h
|
||||
#define dap_session_h
|
||||
|
||||
#include "future.h"
|
||||
#include "io.h"
|
||||
#include "traits.h"
|
||||
#include "typeinfo.h"
|
||||
#include "typeof.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace dap {
|
||||
|
||||
// Forward declarations
|
||||
struct Request;
|
||||
struct Response;
|
||||
struct Event;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Error represents an error message in response to a DAP request.
|
||||
struct Error {
|
||||
Error() = default;
|
||||
Error(const std::string& error);
|
||||
Error(const char* msg, ...);
|
||||
|
||||
// operator bool() returns true if there is an error.
|
||||
inline operator bool() const { return message.size() > 0; }
|
||||
|
||||
std::string message; // empty represents success.
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// ResponseOrError<T>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ResponseOrError holds either the response to a DAP request or an error
|
||||
// message.
|
||||
template <typename T>
|
||||
struct ResponseOrError {
|
||||
using Request = T;
|
||||
|
||||
inline ResponseOrError() = default;
|
||||
inline ResponseOrError(const T& response);
|
||||
inline ResponseOrError(T&& response);
|
||||
inline ResponseOrError(const Error& error);
|
||||
inline ResponseOrError(Error&& error);
|
||||
inline ResponseOrError(const ResponseOrError& other);
|
||||
inline ResponseOrError(ResponseOrError&& other);
|
||||
|
||||
inline ResponseOrError& operator=(const ResponseOrError& other);
|
||||
inline ResponseOrError& operator=(ResponseOrError&& other);
|
||||
|
||||
T response;
|
||||
Error error; // empty represents success.
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(const T& resp) : response(resp) {}
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(T&& resp) : response(std::move(resp)) {}
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(const Error& err) : error(err) {}
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(Error&& err) : error(std::move(err)) {}
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(const ResponseOrError& other)
|
||||
: response(other.response), error(other.error) {}
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(ResponseOrError&& other)
|
||||
: response(std::move(other.response)), error(std::move(other.error)) {}
|
||||
template <typename T>
|
||||
ResponseOrError<T>& ResponseOrError<T>::operator=(
|
||||
const ResponseOrError& other) {
|
||||
response = other.response;
|
||||
error = other.error;
|
||||
return *this;
|
||||
}
|
||||
template <typename T>
|
||||
ResponseOrError<T>& ResponseOrError<T>::operator=(ResponseOrError&& other) {
|
||||
response = std::move(other.response);
|
||||
error = std::move(other.error);
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Session
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Session implements a DAP client or server endpoint.
|
||||
// The general usage is as follows:
|
||||
// (1) Create a session with Session::create().
|
||||
// (2) Register request and event handlers with registerHandler().
|
||||
// (3) Optionally register a protocol error handler with onError().
|
||||
// (3) Bind the session to the remote endpoint with bind().
|
||||
// (4) Send requests or events with send().
|
||||
class Session {
|
||||
template <typename F, int N>
|
||||
using ParamType = traits::ParameterType<F, N>;
|
||||
|
||||
template <typename T>
|
||||
using IsRequest = traits::EnableIfIsType<dap::Request, T>;
|
||||
|
||||
template <typename T>
|
||||
using IsEvent = traits::EnableIfIsType<dap::Event, T>;
|
||||
|
||||
template <typename F>
|
||||
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();
|
||||
|
||||
// ErrorHandler is the type of callback function used for reporting protocol
|
||||
// errors.
|
||||
using ErrorHandler = std::function<void(const char*)>;
|
||||
|
||||
// ClosedHandler is the type of callback function used to signal that a
|
||||
// connected endpoint has closed.
|
||||
using ClosedHandler = std::function<void()>;
|
||||
|
||||
// create() constructs and returns a new Session.
|
||||
static std::unique_ptr<Session> create();
|
||||
|
||||
// onError() registers a error handler that will be called whenever a protocol
|
||||
// error is encountered.
|
||||
// Only one error handler can be bound at any given time, and later calls
|
||||
// will replace the existing error handler.
|
||||
virtual void onError(const ErrorHandler&) = 0;
|
||||
|
||||
// registerHandler() registers a request handler for a specific request type.
|
||||
// The function F must have one of the following signatures:
|
||||
// ResponseOrError<ResponseType>(const RequestType&)
|
||||
// ResponseType(const RequestType&)
|
||||
// Error(const RequestType&)
|
||||
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 = 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 ParamType<F, 0>::Request>
|
||||
inline void registerSentHandler(F&& handler);
|
||||
|
||||
// send() sends the request to the connected endpoint and returns a
|
||||
// future that is assigned the request response or error.
|
||||
template <typename T, typename = IsRequest<T>>
|
||||
future<ResponseOrError<typename T::Response>> send(const T& request);
|
||||
|
||||
// send() sends the event to the connected endpoint.
|
||||
template <typename T, typename = IsEvent<T>>
|
||||
void send(const T& event);
|
||||
|
||||
// bind() connects this Session to an endpoint using connect(), and then
|
||||
// starts processing incoming messages with startProcessingMessages().
|
||||
// onClose is the optional callback which will be called when the session
|
||||
// endpoint has been closed.
|
||||
inline void bind(const std::shared_ptr<Reader>& reader,
|
||||
const std::shared_ptr<Writer>& writer,
|
||||
const ClosedHandler& onClose);
|
||||
inline void bind(const std::shared_ptr<ReaderWriter>& readerWriter,
|
||||
const ClosedHandler& onClose);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Note:
|
||||
// Methods and members below this point are for advanced usage, and are more
|
||||
// likely to change signature than the methods above.
|
||||
// The methods above this point should be sufficient for most use cases.
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// connect() connects this Session to an endpoint.
|
||||
// connect() can only be called once. Repeated calls will raise an error, but
|
||||
// otherwise will do nothing.
|
||||
// Note: This method is used for explicit control over message handling.
|
||||
// Most users will use bind() instead of calling this method directly.
|
||||
virtual void connect(const std::shared_ptr<Reader>&,
|
||||
const std::shared_ptr<Writer>&) = 0;
|
||||
inline void connect(const std::shared_ptr<ReaderWriter>&);
|
||||
|
||||
// startProcessingMessages() starts a new thread to receive and dispatch
|
||||
// incoming messages.
|
||||
// onClose is the optional callback which will be called when the session
|
||||
// endpoint has been closed.
|
||||
// Note: This method is used for explicit control over message handling.
|
||||
// Most users will use bind() instead of calling this method directly.
|
||||
virtual void startProcessingMessages(const ClosedHandler& onClose = {}) = 0;
|
||||
|
||||
// getPayload() blocks until the next incoming message is received, returning
|
||||
// the payload or an empty function if the connection was lost. The returned
|
||||
// payload is function that can be called on any thread to dispatch the
|
||||
// message to the Session handler.
|
||||
// Note: This method is used for explicit control over message handling.
|
||||
// Most users will use bind() instead of calling this method directly.
|
||||
virtual std::function<void()> getPayload() = 0;
|
||||
|
||||
// The callback function type called when a request handler is invoked, and
|
||||
// the request returns a successful result.
|
||||
// 'responseTypeInfo' is the type information of the response data structure.
|
||||
// 'responseData' is a pointer to response payload data.
|
||||
using RequestHandlerSuccessCallback =
|
||||
std::function<void(const TypeInfo* responseTypeInfo,
|
||||
const void* responseData)>;
|
||||
|
||||
// The callback function type used to notify when a DAP request fails.
|
||||
// 'responseTypeInfo' is the type information of the response data structure.
|
||||
// 'message' is the error message
|
||||
using RequestHandlerErrorCallback =
|
||||
std::function<void(const TypeInfo* responseTypeInfo,
|
||||
const Error& message)>;
|
||||
|
||||
// The callback function type used to invoke a request handler.
|
||||
// 'request' is a pointer to the request data structure
|
||||
// 'onSuccess' is the function to call if the request completed succesfully.
|
||||
// 'onError' is the function to call if the request failed.
|
||||
// For each call of the request handler, 'onSuccess' or 'onError' must be
|
||||
// called exactly once.
|
||||
using GenericRequestHandler =
|
||||
std::function<void(const void* request,
|
||||
const RequestHandlerSuccessCallback& onSuccess,
|
||||
const RequestHandlerErrorCallback& onError)>;
|
||||
|
||||
// The callback function type used to handle a response to a request.
|
||||
// 'response' is a pointer to the response data structure. May be nullptr.
|
||||
// 'error' is a pointer to the reponse error message. May be nullptr.
|
||||
// One of 'data' or 'error' will be nullptr.
|
||||
using GenericResponseHandler =
|
||||
std::function<void(const void* response, const Error* error)>;
|
||||
|
||||
// The callback function type used to handle an event.
|
||||
// 'event' is a pointer to the event data structure.
|
||||
using GenericEventHandler = std::function<void(const void* event)>;
|
||||
|
||||
// The callback function type used to notify when a response has been sent
|
||||
// from this session endpoint.
|
||||
// 'response' is a pointer to the response data structure.
|
||||
// 'error' is a pointer to the reponse error message. May be nullptr.
|
||||
using GenericResponseSentHandler =
|
||||
std::function<void(const void* response, const Error* error)>;
|
||||
|
||||
// registerHandler() registers 'handler' as the request handler callback for
|
||||
// requests of the type 'typeinfo'.
|
||||
virtual void registerHandler(const TypeInfo* typeinfo,
|
||||
const GenericRequestHandler& handler) = 0;
|
||||
|
||||
// registerHandler() registers 'handler' as the event handler callback for
|
||||
// events of the type 'typeinfo'.
|
||||
virtual void registerHandler(const TypeInfo* typeinfo,
|
||||
const GenericEventHandler& handler) = 0;
|
||||
|
||||
// registerHandler() registers 'handler' as the response-sent handler function
|
||||
// which is called whenever a response of the type 'typeinfo' is sent from
|
||||
// this session endpoint.
|
||||
virtual void registerHandler(const TypeInfo* typeinfo,
|
||||
const GenericResponseSentHandler& handler) = 0;
|
||||
|
||||
// send() sends a request to the remote endpoint.
|
||||
// 'requestTypeInfo' is the type info of the request data structure.
|
||||
// 'requestTypeInfo' is the type info of the response data structure.
|
||||
// 'request' is a pointer to the request data structure.
|
||||
// 'responseHandler' is the handler function for the response.
|
||||
virtual bool send(const dap::TypeInfo* requestTypeInfo,
|
||||
const dap::TypeInfo* responseTypeInfo,
|
||||
const void* request,
|
||||
const GenericResponseHandler& responseHandler) = 0;
|
||||
|
||||
// send() sends an event to the remote endpoint.
|
||||
// 'eventTypeInfo' is the type info for the event data structure.
|
||||
// 'event' is a pointer to the event data structure.
|
||||
virtual bool send(const TypeInfo* eventTypeInfo, const void* event) = 0;
|
||||
};
|
||||
|
||||
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 RequestHandlerSuccessCallback& onSuccess,
|
||||
const RequestHandlerErrorCallback& onError) {
|
||||
ResponseOrError<ResponseType> res =
|
||||
handler(*reinterpret_cast<const RequestType*>(args));
|
||||
if (res.error) {
|
||||
onError(TypeOf<ResponseType>::type(), res.error);
|
||||
} else {
|
||||
onSuccess(TypeOf<ResponseType>::type(), &res.response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 RequestHandlerSuccessCallback& onSuccess,
|
||||
const RequestHandlerErrorCallback&) {
|
||||
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 RequestHandlerSuccessCallback& onSuccess,
|
||||
const RequestHandlerErrorCallback& 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>
|
||||
Session::IsEvent<T> Session::registerHandler(F&& handler) {
|
||||
auto cb = [handler](const void* args) {
|
||||
handler(*reinterpret_cast<const T*>(args));
|
||||
};
|
||||
const TypeInfo* typeinfo = TypeOf<T>::type();
|
||||
registerHandler(typeinfo, cb);
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
void Session::registerSentHandler(F&& handler) {
|
||||
auto cb = [handler](const void* response, const Error* error) {
|
||||
if (error != nullptr) {
|
||||
handler(ResponseOrError<T>(*error));
|
||||
} else {
|
||||
handler(ResponseOrError<T>(*reinterpret_cast<const T*>(response)));
|
||||
}
|
||||
};
|
||||
const TypeInfo* typeinfo = TypeOf<T>::type();
|
||||
registerHandler(typeinfo, cb);
|
||||
}
|
||||
|
||||
template <typename T, typename>
|
||||
future<ResponseOrError<typename T::Response>> Session::send(const T& request) {
|
||||
using Response = typename T::Response;
|
||||
promise<ResponseOrError<Response>> promise;
|
||||
auto sent = send(TypeOf<T>::type(), TypeOf<Response>::type(), &request,
|
||||
[=](const void* result, const Error* error) {
|
||||
if (error != nullptr) {
|
||||
promise.set_value(ResponseOrError<Response>(*error));
|
||||
} else {
|
||||
promise.set_value(ResponseOrError<Response>(
|
||||
*reinterpret_cast<const Response*>(result)));
|
||||
}
|
||||
});
|
||||
if (!sent) {
|
||||
promise.set_value(Error("Failed to send request"));
|
||||
}
|
||||
return promise.get_future();
|
||||
}
|
||||
|
||||
template <typename T, typename>
|
||||
void Session::send(const T& event) {
|
||||
const TypeInfo* typeinfo = TypeOf<T>::type();
|
||||
send(typeinfo, &event);
|
||||
}
|
||||
|
||||
void Session::connect(const std::shared_ptr<ReaderWriter>& rw) {
|
||||
connect(rw, rw);
|
||||
}
|
||||
|
||||
void Session::bind(const std::shared_ptr<dap::Reader>& r,
|
||||
const std::shared_ptr<dap::Writer>& w,
|
||||
const ClosedHandler& onClose = {}) {
|
||||
connect(r, w);
|
||||
startProcessingMessages(onClose);
|
||||
}
|
||||
|
||||
void Session::bind(const std::shared_ptr<ReaderWriter>& rw,
|
||||
const ClosedHandler& onClose = {}) {
|
||||
bind(rw, rw, onClose);
|
||||
}
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_session_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_TY`,
|
||||
// otherwise an invalid type.
|
||||
template <typename BASE, typename T, typename TRUE_TY = void>
|
||||
using EnableIfIsType = EnableIf<IsTypeOrDerived<BASE, T>::value, TRUE_TY>;
|
||||
|
||||
// If the function-like `F` has a matching signature to the function-like `S`
|
||||
// then EnableIfHasSignature resolves to type `TRUE_TY`, otherwise an invalid type.
|
||||
template <typename F, typename S, typename TRUE_TY = void>
|
||||
using EnableIfHasSignature = EnableIf<HasSignature<F, S>::value, TRUE_TY>;
|
||||
|
||||
} // namespace traits
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_traits_h
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2019 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_typeinfo_h
|
||||
#define dap_typeinfo_h
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace dap {
|
||||
|
||||
class any;
|
||||
class Deserializer;
|
||||
class Serializer;
|
||||
|
||||
// The TypeInfo interface provides basic runtime type information about DAP
|
||||
// types. TypeInfo is used by the serialization system to encode and decode DAP
|
||||
// requests, responses, events and structs.
|
||||
struct TypeInfo {
|
||||
virtual ~TypeInfo();
|
||||
virtual std::string name() const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
virtual size_t alignment() const = 0;
|
||||
virtual void construct(void*) const = 0;
|
||||
virtual void copyConstruct(void* dst, const void* src) const = 0;
|
||||
virtual void destruct(void*) const = 0;
|
||||
virtual bool deserialize(const Deserializer*, void*) const = 0;
|
||||
virtual bool serialize(Serializer*, const void*) const = 0;
|
||||
|
||||
// create() allocates and constructs the TypeInfo of type T, registers the
|
||||
// pointer for deletion on cppdap library termination, and returns the pointer
|
||||
// to T.
|
||||
template <typename T, typename... ARGS>
|
||||
static T* create(ARGS&&... args) {
|
||||
auto typeinfo = new T(std::forward<ARGS>(args)...);
|
||||
deleteOnExit(typeinfo);
|
||||
return typeinfo;
|
||||
}
|
||||
|
||||
private:
|
||||
// deleteOnExit() ensures that the TypeInfo is destructed and deleted on
|
||||
// library termination.
|
||||
static void deleteOnExit(TypeInfo*);
|
||||
};
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_typeinfo_h
|
||||
@@ -0,0 +1,266 @@
|
||||
// Copyright 2019 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_typeof_h
|
||||
#define dap_typeof_h
|
||||
|
||||
#include "typeinfo.h"
|
||||
#include "types.h"
|
||||
|
||||
#include "serialization.h"
|
||||
|
||||
namespace dap {
|
||||
|
||||
// BasicTypeInfo is an implementation of the TypeInfo interface for the simple
|
||||
// template type T.
|
||||
template <typename T>
|
||||
struct BasicTypeInfo : public TypeInfo {
|
||||
constexpr BasicTypeInfo(std::string&& name) : name_(std::move(name)) {}
|
||||
|
||||
// TypeInfo compliance
|
||||
inline std::string name() const override { return name_; }
|
||||
inline size_t size() const override { return sizeof(T); }
|
||||
inline size_t alignment() const override { return alignof(T); }
|
||||
inline void construct(void* ptr) const override { new (ptr) T(); }
|
||||
inline void copyConstruct(void* dst, const void* src) const override {
|
||||
new (dst) T(*reinterpret_cast<const T*>(src));
|
||||
}
|
||||
inline void destruct(void* ptr) const override {
|
||||
reinterpret_cast<T*>(ptr)->~T();
|
||||
}
|
||||
inline bool deserialize(const Deserializer* d, void* ptr) const override {
|
||||
return d->deserialize(reinterpret_cast<T*>(ptr));
|
||||
}
|
||||
inline bool serialize(Serializer* s, const void* ptr) const override {
|
||||
return s->serialize(*reinterpret_cast<const T*>(ptr));
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
// TypeOf has a template specialization for each DAP type, each declaring a
|
||||
// const TypeInfo* type() static member function that describes type T.
|
||||
template <typename T>
|
||||
struct TypeOf {};
|
||||
|
||||
template <>
|
||||
struct TypeOf<boolean> {
|
||||
static const TypeInfo* type();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeOf<string> {
|
||||
static const TypeInfo* type();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeOf<integer> {
|
||||
static const TypeInfo* type();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeOf<number> {
|
||||
static const TypeInfo* type();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeOf<object> {
|
||||
static const TypeInfo* type();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeOf<any> {
|
||||
static const TypeInfo* type();
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeOf<null> {
|
||||
static const TypeInfo* type();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TypeOf<array<T>> {
|
||||
static inline const TypeInfo* type() {
|
||||
static auto typeinfo = TypeInfo::create<BasicTypeInfo<array<T>>>(
|
||||
"array<" + TypeOf<T>::type()->name() + ">");
|
||||
return typeinfo;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
struct TypeOf<variant<T0, Types...>> {
|
||||
static inline const TypeInfo* type() {
|
||||
static auto typeinfo =
|
||||
TypeInfo::create<BasicTypeInfo<variant<T0, Types...>>>("variant");
|
||||
return typeinfo;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TypeOf<optional<T>> {
|
||||
static inline const TypeInfo* type() {
|
||||
static auto typeinfo = TypeInfo::create<BasicTypeInfo<optional<T>>>(
|
||||
"optional<" + TypeOf<T>::type()->name() + ">");
|
||||
return typeinfo;
|
||||
}
|
||||
};
|
||||
|
||||
// DAP_OFFSETOF() macro is a generalization of the offsetof() macro defined in
|
||||
// <cstddef>. It evaluates to the offset of the given field, with fewer
|
||||
// restrictions than offsetof(). We cast the address '32' and subtract it again,
|
||||
// because null-dereference is undefined behavior.
|
||||
#define DAP_OFFSETOF(s, m) \
|
||||
((int)(size_t) & reinterpret_cast<const volatile char&>((((s*)32)->m)) - 32)
|
||||
|
||||
// internal functionality
|
||||
namespace detail {
|
||||
template <class T, class M>
|
||||
M member_type(M T::*);
|
||||
} // namespace detail
|
||||
|
||||
// DAP_TYPEOF() returns the type of the struct (s) member (m).
|
||||
#define DAP_TYPEOF(s, m) decltype(detail::member_type(&s::m))
|
||||
|
||||
// DAP_FIELD() declares a structure field for the DAP_IMPLEMENT_STRUCT_TYPEINFO
|
||||
// macro.
|
||||
// FIELD is the name of the struct field.
|
||||
// NAME is the serialized name of the field, as described by the DAP
|
||||
// specification.
|
||||
#define DAP_FIELD(FIELD, NAME) \
|
||||
::dap::Field { \
|
||||
NAME, DAP_OFFSETOF(StructTy, FIELD), \
|
||||
TypeOf<DAP_TYPEOF(StructTy, FIELD)>::type(), \
|
||||
}
|
||||
|
||||
// DAP_DECLARE_STRUCT_TYPEINFO() declares a TypeOf<> specialization for STRUCT.
|
||||
// Must be used within the 'dap' namespace.
|
||||
#define DAP_DECLARE_STRUCT_TYPEINFO(STRUCT) \
|
||||
template <> \
|
||||
struct TypeOf<STRUCT> { \
|
||||
static constexpr bool has_custom_serialization = true; \
|
||||
static const TypeInfo* type(); \
|
||||
static bool deserializeFields(const Deserializer*, void* obj); \
|
||||
static bool serializeFields(FieldSerializer*, const void* obj); \
|
||||
}
|
||||
|
||||
// DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION() implements the deserializeFields()
|
||||
// and serializeFields() static methods of a TypeOf<> specialization. Used
|
||||
// internally by DAP_IMPLEMENT_STRUCT_TYPEINFO() and
|
||||
// DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT().
|
||||
// You probably do not want to use this directly.
|
||||
#define DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, ...) \
|
||||
bool TypeOf<STRUCT>::deserializeFields(const Deserializer* fd, void* obj) { \
|
||||
using StructTy = STRUCT; \
|
||||
(void)sizeof(StructTy); /* avoid unused 'using' warning */ \
|
||||
for (auto field : std::initializer_list<Field>{__VA_ARGS__}) { \
|
||||
if (!fd->field(field.name, [&](Deserializer* d) { \
|
||||
auto ptr = reinterpret_cast<uint8_t*>(obj) + field.offset; \
|
||||
return field.type->deserialize(d, ptr); \
|
||||
})) { \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
bool TypeOf<STRUCT>::serializeFields(FieldSerializer* fs, const void* obj) {\
|
||||
using StructTy = STRUCT; \
|
||||
(void)sizeof(StructTy); /* avoid unused 'using' warning */ \
|
||||
for (auto field : std::initializer_list<Field>{__VA_ARGS__}) { \
|
||||
if (!fs->field(field.name, [&](Serializer* s) { \
|
||||
auto ptr = reinterpret_cast<const uint8_t*>(obj) + field.offset; \
|
||||
return field.type->serialize(s, ptr); \
|
||||
})) { \
|
||||
return false; \
|
||||
} \
|
||||
} \
|
||||
return true; \
|
||||
}
|
||||
|
||||
// DAP_IMPLEMENT_STRUCT_TYPEINFO() implements the type() member function for the
|
||||
// TypeOf<> specialization for STRUCT.
|
||||
// STRUCT is the structure typename.
|
||||
// NAME is the serialized name of the structure, as described by the DAP
|
||||
// specification. The variadic (...) parameters should be a repeated list of
|
||||
// DAP_FIELD()s, one for each field of the struct.
|
||||
// Must be used within the 'dap' namespace.
|
||||
#define DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, ...) \
|
||||
DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, __VA_ARGS__) \
|
||||
const ::dap::TypeInfo* TypeOf<STRUCT>::type() { \
|
||||
struct TI : BasicTypeInfo<STRUCT> { \
|
||||
TI() : BasicTypeInfo<STRUCT>(NAME) {} \
|
||||
bool deserialize(const Deserializer* d, void* obj) const override { \
|
||||
return deserializeFields(d, obj); \
|
||||
} \
|
||||
bool serialize(Serializer* s, const void* obj) const override { \
|
||||
return s->object( \
|
||||
[&](FieldSerializer* fs) { return serializeFields(fs, obj); }); \
|
||||
} \
|
||||
}; \
|
||||
static TI typeinfo; \
|
||||
return &typeinfo; \
|
||||
}
|
||||
|
||||
// DAP_STRUCT_TYPEINFO() is a helper for declaring and implementing a TypeOf<>
|
||||
// specialization for STRUCT in a single statement.
|
||||
// Must be used within the 'dap' namespace.
|
||||
#define DAP_STRUCT_TYPEINFO(STRUCT, NAME, ...) \
|
||||
DAP_DECLARE_STRUCT_TYPEINFO(STRUCT); \
|
||||
DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, __VA_ARGS__)
|
||||
|
||||
// DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT() implements the type() member function for
|
||||
// the TypeOf<> specialization for STRUCT that derives from BASE.
|
||||
// STRUCT is the structure typename.
|
||||
// BASE is the base structure typename.
|
||||
// NAME is the serialized name of the structure, as described by the DAP
|
||||
// specification. The variadic (...) parameters should be a repeated list of
|
||||
// DAP_FIELD()s, one for each field of the struct.
|
||||
// Must be used within the 'dap' namespace.
|
||||
#define DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, ...) \
|
||||
static_assert(std::is_base_of<BASE, STRUCT>::value, \
|
||||
#STRUCT " does not derive from " #BASE); \
|
||||
DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, __VA_ARGS__) \
|
||||
const ::dap::TypeInfo* TypeOf<STRUCT>::type() { \
|
||||
struct TI : BasicTypeInfo<STRUCT> { \
|
||||
TI() : BasicTypeInfo<STRUCT>(NAME) {} \
|
||||
bool deserialize(const Deserializer* d, void* obj) const override { \
|
||||
auto derived = static_cast<STRUCT*>(obj); \
|
||||
auto base = static_cast<BASE*>(obj); \
|
||||
return TypeOf<BASE>::deserializeFields(d, base) && \
|
||||
deserializeFields(d, derived); \
|
||||
} \
|
||||
bool serialize(Serializer* s, const void* obj) const override { \
|
||||
return s->object([&](FieldSerializer* fs) { \
|
||||
auto derived = static_cast<const STRUCT*>(obj); \
|
||||
auto base = static_cast<const BASE*>(obj); \
|
||||
return TypeOf<BASE>::serializeFields(fs, base) && \
|
||||
serializeFields(fs, derived); \
|
||||
}); \
|
||||
} \
|
||||
}; \
|
||||
static TI typeinfo; \
|
||||
return &typeinfo; \
|
||||
}
|
||||
|
||||
// DAP_STRUCT_TYPEINFO_EXT() is a helper for declaring and implementing a
|
||||
// TypeOf<> specialization for STRUCT that derives from BASE in a single
|
||||
// statement.
|
||||
// Must be used within the 'dap' namespace.
|
||||
#define DAP_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, ...) \
|
||||
DAP_DECLARE_STRUCT_TYPEINFO(STRUCT); \
|
||||
DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, __VA_ARGS__)
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_typeof_h
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// This file holds the basic serializable types used by the debug adapter
|
||||
// protocol.
|
||||
|
||||
#ifndef dap_types_h
|
||||
#define dap_types_h
|
||||
|
||||
#include "any.h"
|
||||
#include "optional.h"
|
||||
#include "variant.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace dap {
|
||||
|
||||
// string is a sequence of characters.
|
||||
// string defaults to an empty string.
|
||||
using string = std::string;
|
||||
|
||||
// boolean holds a true or false value.
|
||||
// boolean defaults to false.
|
||||
class boolean {
|
||||
public:
|
||||
inline boolean() : val(false) {}
|
||||
inline boolean(bool i) : val(i) {}
|
||||
inline operator bool() const { return val; }
|
||||
inline boolean& operator=(bool i) {
|
||||
val = i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool val;
|
||||
};
|
||||
|
||||
// integer holds a whole signed number.
|
||||
// integer defaults to 0.
|
||||
class integer {
|
||||
public:
|
||||
inline integer() : val(0) {}
|
||||
inline integer(int64_t i) : val(i) {}
|
||||
inline operator int64_t() const { return val; }
|
||||
inline integer& operator=(int64_t i) {
|
||||
val = i;
|
||||
return *this;
|
||||
}
|
||||
inline integer operator++(int) {
|
||||
auto copy = *this;
|
||||
val++;
|
||||
return copy;
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t val;
|
||||
};
|
||||
|
||||
// number holds a 64-bit floating point number.
|
||||
// number defaults to 0.
|
||||
class number {
|
||||
public:
|
||||
inline number() : val(0.0) {}
|
||||
inline number(double i) : val(i) {}
|
||||
inline operator double() const { return val; }
|
||||
inline number& operator=(double i) {
|
||||
val = i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
double val;
|
||||
};
|
||||
|
||||
// array is a list of items of type T.
|
||||
// array defaults to an empty list.
|
||||
template <typename T>
|
||||
using array = std::vector<T>;
|
||||
|
||||
// object is a map of string to any.
|
||||
// object defaults to an empty map.
|
||||
using object = std::unordered_map<string, any>;
|
||||
|
||||
// null represents no value.
|
||||
// null is used by any to check for no-value.
|
||||
using null = std::nullptr_t;
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_types_h
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2019 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_variant_h
|
||||
#define dap_variant_h
|
||||
|
||||
#include "any.h"
|
||||
|
||||
namespace dap {
|
||||
|
||||
// internal functionality
|
||||
namespace detail {
|
||||
template <typename T, typename...>
|
||||
struct TypeIsIn {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <typename T, typename List0, typename... ListN>
|
||||
struct TypeIsIn<T, List0, ListN...> {
|
||||
static constexpr bool value =
|
||||
std::is_same<T, List0>::value || TypeIsIn<T, ListN...>::value;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// variant represents a type-safe union of DAP types.
|
||||
// variant can hold a value of any of the template argument types.
|
||||
// variant defaults to a default-constructed T0.
|
||||
template <typename T0, typename... Types>
|
||||
class variant {
|
||||
public:
|
||||
// constructors
|
||||
inline variant();
|
||||
template <typename T>
|
||||
inline variant(const T& val);
|
||||
|
||||
// assignment
|
||||
template <typename T>
|
||||
inline variant& operator=(const T& val);
|
||||
|
||||
// get() returns the contained value of the type T.
|
||||
// If the any does not contain a value of type T, then get() will assert.
|
||||
template <typename T>
|
||||
inline T& get() const;
|
||||
|
||||
// is() returns true iff the contained value is of type T.
|
||||
template <typename T>
|
||||
inline bool is() const;
|
||||
|
||||
// accepts() returns true iff the variant accepts values of type T.
|
||||
template <typename T>
|
||||
static constexpr bool accepts();
|
||||
|
||||
private:
|
||||
friend class Serializer;
|
||||
friend class Deserializer;
|
||||
any value;
|
||||
};
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
variant<T0, Types...>::variant() : value(T0()) {}
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
template <typename T>
|
||||
variant<T0, Types...>::variant(const T& v) : value(v) {
|
||||
static_assert(accepts<T>(), "variant does not accept template type T");
|
||||
}
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
template <typename T>
|
||||
variant<T0, Types...>& variant<T0, Types...>::operator=(const T& v) {
|
||||
static_assert(accepts<T>(), "variant does not accept template type T");
|
||||
value = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
template <typename T>
|
||||
T& variant<T0, Types...>::get() const {
|
||||
static_assert(accepts<T>(), "variant does not accept template type T");
|
||||
return value.get<T>();
|
||||
}
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
template <typename T>
|
||||
bool variant<T0, Types...>::is() const {
|
||||
return value.is<T>();
|
||||
}
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
template <typename T>
|
||||
constexpr bool variant<T0, Types...>::accepts() {
|
||||
return detail::TypeIsIn<T, T0, Types...>::value;
|
||||
}
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_variant_h
|
||||
Reference in New Issue
Block a user