Merge branch 'upstream-cppdap' into import-cppdap

* upstream-cppdap:
  cppdap 2023-05-26 (03cc1867)
This commit is contained in:
Glen Chung
2023-05-26 09:33:57 -04:00
committed by Brad King
54 changed files with 11861 additions and 0 deletions
+211
View File
@@ -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
+35
View File
@@ -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
+179
View File
@@ -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
+97
View File
@@ -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
+62
View File
@@ -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
+263
View File
@@ -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
+449
View File
@@ -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
+159
View File
@@ -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
+59
View File
@@ -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
+266
View File
@@ -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
+104
View File
@@ -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
+108
View File
@@ -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