Initial drop of cppdap
This commit is contained in:
182
include/dap/any.h
Normal file
182
include/dap/any.h
Normal file
@@ -0,0 +1,182 @@
|
||||
// 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>
|
||||
|
||||
namespace dap {
|
||||
|
||||
template <typename T>
|
||||
struct TypeOf;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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:
|
||||
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 : value(other.value), type(other.type) {
|
||||
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 {
|
||||
value = rhs.value;
|
||||
type = rhs.type;
|
||||
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 {
|
||||
*reinterpret_cast<T*>(value) = val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& any::get() const {
|
||||
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
|
||||
95
include/dap/io.h
Normal file
95
include/dap/io.h
Normal file
@@ -0,0 +1,95 @@
|
||||
// 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 <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 {
|
||||
// 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
|
||||
55
include/dap/network.h
Normal file
55
include/dap/network.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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.
|
||||
std::shared_ptr<ReaderWriter> connect(const char* addr, int port);
|
||||
|
||||
// Server implements a basic TCP server.
|
||||
class Server {
|
||||
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 = OnError()) = 0;
|
||||
|
||||
// stop() stops listening for connections.
|
||||
// stop() is implicitly called on destruction.
|
||||
virtual void stop() = 0;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_network_h
|
||||
271
include/dap/optional.h
Normal file
271
include/dap/optional.h
Normal file
@@ -0,0 +1,271 @@
|
||||
// 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>
|
||||
|
||||
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 T& value(const T& defaultValue);
|
||||
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::move(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>
|
||||
T& optional<T>::value(const T& defaultValue) {
|
||||
if (!has_value()) {
|
||||
return defaultValue;
|
||||
}
|
||||
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::move(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
|
||||
2441
include/dap/protocol.h
Normal file
2441
include/dap/protocol.h
Normal file
File diff suppressed because it is too large
Load Diff
256
include/dap/serialization.h
Normal file
256
include/dap/serialization.h
Normal file
@@ -0,0 +1,256 @@
|
||||
// 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 <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:
|
||||
// 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 a list of fields and stores them into the object.
|
||||
inline bool deserialize(void* object,
|
||||
const std::initializer_list<Field>&) 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);
|
||||
}
|
||||
|
||||
bool Deserializer::deserialize(
|
||||
void* object,
|
||||
const std::initializer_list<Field>& fields) const {
|
||||
for (auto const& f : fields) {
|
||||
if (!field(f.name, [&](Deserializer* d) {
|
||||
auto ptr = reinterpret_cast<uint8_t*>(object) + f.offset;
|
||||
return f.type->deserialize(d, ptr);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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:
|
||||
using FieldSerializer = std::function<bool(Serializer*)>;
|
||||
template <typename T>
|
||||
using IsFieldSerializer = std::is_convertible<T, FieldSerializer>;
|
||||
|
||||
// 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 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;
|
||||
|
||||
// field() encodes a field to the struct object referenced by this Serializer.
|
||||
// The FieldSerializer will be called with a Serializer used to encode the
|
||||
// field's data.
|
||||
virtual bool field(const std::string& name, const 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...>&);
|
||||
|
||||
// serialize() encodes all the provided fields of the given object.
|
||||
inline bool serialize(const void* object,
|
||||
const std::initializer_list<Field>&);
|
||||
|
||||
// deserialize() encodes the given string.
|
||||
inline bool serialize(const char* v);
|
||||
|
||||
// field() encodes the field with the given name and value.
|
||||
template <
|
||||
typename T,
|
||||
typename = typename std::enable_if<!IsFieldSerializer<T>::value>::type>
|
||||
inline bool field(const std::string& name, const T& v);
|
||||
};
|
||||
|
||||
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 void* object,
|
||||
const std::initializer_list<Field>& fields) {
|
||||
for (auto const& f : fields) {
|
||||
if (!field(f.name, [&](Serializer* d) {
|
||||
auto ptr = reinterpret_cast<const uint8_t*>(object) + f.offset;
|
||||
return f.type->serialize(d, ptr);
|
||||
}))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serializer::serialize(const char* v) {
|
||||
return serialize(std::string(v));
|
||||
}
|
||||
|
||||
template <typename T, typename>
|
||||
bool Serializer::field(const std::string& name, const T& v) {
|
||||
return this->field(name, [&](Serializer* s) { return s->serialize(v); });
|
||||
}
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_serialization_h
|
||||
283
include/dap/session.h
Normal file
283
include/dap/session.h
Normal file
@@ -0,0 +1,283 @@
|
||||
// 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 "io.h"
|
||||
#include "typeinfo.h"
|
||||
#include "typeof.h"
|
||||
|
||||
#include <functional>
|
||||
#include <future>
|
||||
|
||||
namespace dap {
|
||||
|
||||
// Forward declarations
|
||||
struct Request;
|
||||
struct Response;
|
||||
struct Event;
|
||||
|
||||
// internal functionality
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct traits {
|
||||
static constexpr bool isRequest = std::is_base_of<dap::Request, T>::value;
|
||||
static constexpr bool isResponse = std::is_base_of<dap::Response, T>::value;
|
||||
static constexpr bool isEvent = std::is_base_of<dap::Event, T>::value;
|
||||
};
|
||||
|
||||
// ArgTy<F>::type resolves to the first argument type of the function F.
|
||||
// F can be a function, static member function, or lambda.
|
||||
template <typename F>
|
||||
struct ArgTy {
|
||||
using type = typename ArgTy<decltype(&F::operator())>::type;
|
||||
};
|
||||
|
||||
template <typename R, typename Arg>
|
||||
struct ArgTy<R (*)(Arg)> {
|
||||
using type = typename std::decay<Arg>::type;
|
||||
};
|
||||
|
||||
template <typename R, typename C, typename Arg>
|
||||
struct ArgTy<R (C::*)(Arg) const> {
|
||||
using type = typename std::decay<Arg>::type;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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(const Error& error);
|
||||
inline ResponseOrError(const ResponseOrError& other);
|
||||
|
||||
T response;
|
||||
Error error; // empty represents success.
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(const T& response) : response(response) {}
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(const Error& error) : error(error) {}
|
||||
template <typename T>
|
||||
ResponseOrError<T>::ResponseOrError(const ResponseOrError& other)
|
||||
: response(other.response), error(other.error) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 T>
|
||||
using IsRequest = typename std::enable_if<detail::traits<T>::isRequest>::type;
|
||||
|
||||
template <typename T>
|
||||
using IsEvent = typename std::enable_if<detail::traits<T>::isEvent>::type;
|
||||
|
||||
template <typename F>
|
||||
using ArgTy = typename detail::ArgTy<F>::type;
|
||||
|
||||
public:
|
||||
virtual ~Session() = default;
|
||||
|
||||
// ErrorHandler is the type of callback function used for reporting protocol
|
||||
// errors.
|
||||
using ErrorHandler = std::function<void(const char*)>;
|
||||
|
||||
// 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 = ArgTy<F>>
|
||||
inline IsRequest<RequestType> registerHandler(F&& handler);
|
||||
|
||||
// registerHandler() registers a event handler for a specific event type.
|
||||
// The function F must have the following signature:
|
||||
// void(const EventType&)
|
||||
template <typename F, typename EventType = ArgTy<F>>
|
||||
inline IsEvent<EventType> registerHandler(F&& handler);
|
||||
|
||||
// registerSentHandler() registers the function F to be called when a response
|
||||
// of the specific type has been sent.
|
||||
// The function F must have the following signature:
|
||||
// void(const ResponseOrError<ResponseType>&)
|
||||
template <typename F, typename ResponseType = typename ArgTy<F>::Request>
|
||||
inline void registerSentHandler(F&& handler);
|
||||
|
||||
// send() sends the request to the connected endpoint and returns a
|
||||
// std::future that is assigned the request response or error.
|
||||
template <typename T, typename = IsRequest<T>>
|
||||
std::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.
|
||||
// bind() can only be called once. Repeated calls will raise an error, but
|
||||
// otherwise will do nothing.
|
||||
virtual void bind(const std::shared_ptr<Reader>&,
|
||||
const std::shared_ptr<Writer>&) = 0;
|
||||
inline void bind(const std::shared_ptr<ReaderWriter>&);
|
||||
|
||||
protected:
|
||||
using RequestSuccessCallback =
|
||||
std::function<void(const TypeInfo*, const void*)>;
|
||||
|
||||
using RequestErrorCallback =
|
||||
std::function<void(const TypeInfo*, const Error& message)>;
|
||||
|
||||
using GenericResponseHandler = std::function<void(const void*, const Error*)>;
|
||||
|
||||
using GenericRequestHandler =
|
||||
std::function<void(const void* args,
|
||||
const RequestSuccessCallback& onSuccess,
|
||||
const RequestErrorCallback& onError)>;
|
||||
|
||||
using GenericEventHandler = std::function<void(const void* args)>;
|
||||
|
||||
using GenericResponseSentHandler =
|
||||
std::function<void(const void* response, const Error* error)>;
|
||||
|
||||
virtual void registerHandler(const TypeInfo* typeinfo,
|
||||
const GenericRequestHandler& handler) = 0;
|
||||
|
||||
virtual void registerHandler(const TypeInfo* typeinfo,
|
||||
const GenericEventHandler& handler) = 0;
|
||||
|
||||
virtual void registerHandler(const TypeInfo* typeinfo,
|
||||
const GenericResponseSentHandler& handler) = 0;
|
||||
|
||||
virtual bool send(const dap::TypeInfo* typeinfo,
|
||||
const void* request,
|
||||
const GenericResponseHandler& responseHandler) = 0;
|
||||
|
||||
virtual bool send(const TypeInfo*, const void* event) = 0;
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
Session::IsRequest<T> Session::registerHandler(F&& handler) {
|
||||
using ResponseType = typename T::Response;
|
||||
auto cb = [handler](const void* args, const RequestSuccessCallback& onSuccess,
|
||||
const RequestErrorCallback& onError) {
|
||||
ResponseOrError<ResponseType> res =
|
||||
handler(*reinterpret_cast<const T*>(args));
|
||||
if (res.error) {
|
||||
onError(TypeOf<ResponseType>::type(), res.error);
|
||||
} else {
|
||||
onSuccess(TypeOf<ResponseType>::type(), &res.response);
|
||||
}
|
||||
};
|
||||
const TypeInfo* typeinfo = TypeOf<T>::type();
|
||||
registerHandler(typeinfo, cb);
|
||||
}
|
||||
|
||||
template <typename F, typename 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>
|
||||
std::future<ResponseOrError<typename T::Response>> Session::send(
|
||||
const T& request) {
|
||||
using Response = typename T::Response;
|
||||
auto promise = std::make_shared<std::promise<ResponseOrError<Response>>>();
|
||||
const TypeInfo* typeinfo = TypeOf<T>::type();
|
||||
auto sent =
|
||||
send(typeinfo, &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::bind(const std::shared_ptr<ReaderWriter>& rw) {
|
||||
bind(rw, rw);
|
||||
}
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_session_h
|
||||
43
include/dap/typeinfo.h
Normal file
43
include/dap/typeinfo.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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 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;
|
||||
};
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_typeinfo_h
|
||||
182
include/dap/typeof.h
Normal file
182
include/dap/typeof.h
Normal file
@@ -0,0 +1,182 @@
|
||||
// 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 {
|
||||
BasicTypeInfo(const std::string& name) : name_(name) {}
|
||||
|
||||
// TypeInfo compliance
|
||||
inline std::string name() const { return name_; }
|
||||
inline size_t size() const { return sizeof(T); }
|
||||
inline size_t alignment() const { return alignof(T); }
|
||||
inline void construct(void* ptr) const { new (ptr) T(); }
|
||||
inline void copyConstruct(void* dst, const void* src) const {
|
||||
new (dst) T(*reinterpret_cast<const T*>(src));
|
||||
}
|
||||
inline void destruct(void* ptr) const { reinterpret_cast<T*>(ptr)->~T(); }
|
||||
inline bool deserialize(const Deserializer* d, void* ptr) const {
|
||||
return d->deserialize(reinterpret_cast<T*>(ptr));
|
||||
}
|
||||
inline bool serialize(Serializer* s, const void* ptr) const {
|
||||
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 BasicTypeInfo<array<T>> typeinfo("array<" +
|
||||
TypeOf<T>::type()->name() + ">");
|
||||
return &typeinfo;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T0, typename... Types>
|
||||
struct TypeOf<variant<T0, Types...>> {
|
||||
static inline const TypeInfo* type() {
|
||||
static BasicTypeInfo<variant<T0, Types...>> typeinfo("variant");
|
||||
return &typeinfo;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TypeOf<optional<T>> {
|
||||
static inline const TypeInfo* type() {
|
||||
static BasicTypeInfo<optional<T>> typeinfo("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.
|
||||
#define DAP_DECLARE_STRUCT_TYPEINFO(STRUCT) \
|
||||
template <> \
|
||||
struct TypeOf<STRUCT> { \
|
||||
static constexpr bool has_custom_serialization = true; \
|
||||
static const TypeInfo* type(); \
|
||||
}
|
||||
|
||||
// DAP_DECLARE_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.
|
||||
#define DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, ...) \
|
||||
const TypeInfo* TypeOf<STRUCT>::type() { \
|
||||
using StructTy = STRUCT; \
|
||||
struct TI : BasicTypeInfo<StructTy> { \
|
||||
TI() : BasicTypeInfo<StructTy>(NAME) {} \
|
||||
bool deserialize(const Deserializer* d, void* ptr) const override { \
|
||||
return d->deserialize(ptr, {__VA_ARGS__}); \
|
||||
} \
|
||||
bool serialize(Serializer* s, const void* ptr) const override { \
|
||||
return s->serialize(ptr, {__VA_ARGS__}); \
|
||||
} \
|
||||
}; \
|
||||
static TI typeinfo; \
|
||||
return &typeinfo; \
|
||||
}
|
||||
|
||||
// DAP_STRUCT_TYPEINFO() is a helper for declaring and implementing a TypeOf<>
|
||||
// specialization for STRUCT in a single statement.
|
||||
#define DAP_STRUCT_TYPEINFO(STRUCT, NAME, ...) \
|
||||
DAP_DECLARE_STRUCT_TYPEINFO(STRUCT); \
|
||||
DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, __VA_ARGS__)
|
||||
|
||||
} // namespace dap
|
||||
|
||||
#endif // dap_typeof_h
|
||||
102
include/dap/types.h
Normal file
102
include/dap/types.h
Normal file
@@ -0,0 +1,102 @@
|
||||
// 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>
|
||||
|
||||
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(int i) : val(i) {}
|
||||
inline operator int() const { return val; }
|
||||
inline integer& operator=(int i) {
|
||||
val = i;
|
||||
return *this;
|
||||
}
|
||||
inline integer operator++(int) {
|
||||
auto copy = *this;
|
||||
val++;
|
||||
return copy;
|
||||
}
|
||||
|
||||
private:
|
||||
int 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
include/dap/variant.h
Normal file
108
include/dap/variant.h
Normal 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& value) : value(value) {
|
||||
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