1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef dap_typeof_h
16#define dap_typeof_h
17
18#include "typeinfo.h"
19#include "types.h"
20
21#include "serialization.h"
22
23namespace dap {
24
25// BasicTypeInfo is an implementation of the TypeInfo interface for the simple
26// template type T.
27template <typename T>
28struct BasicTypeInfo : public TypeInfo {
29 constexpr BasicTypeInfo(std::string&& name) : name_(std::move(name)) {}
30
31 // TypeInfo compliance
32 inline std::string name() const override { return name_; }
33 inline size_t size() const override { return sizeof(T); }
34 inline size_t alignment() const override { return alignof(T); }
35 inline void construct(void* ptr) const override { new (ptr) T(); }
36 inline void copyConstruct(void* dst, const void* src) const override {
37 new (dst) T(*reinterpret_cast<const T*>(src));
38 }
39 inline void destruct(void* ptr) const override {
40 reinterpret_cast<T*>(ptr)->~T();
41 }
42 inline bool deserialize(const Deserializer* d, void* ptr) const override {
43 return d->deserialize(reinterpret_cast<T*>(ptr));
44 }
45 inline bool serialize(Serializer* s, const void* ptr) const override {
46 return s->serialize(*reinterpret_cast<const T*>(ptr));
47 }
48
49 private:
50 std::string name_;
51};
52
53// TypeOf has a template specialization for each DAP type, each declaring a
54// const TypeInfo* type() static member function that describes type T.
55template <typename T>
56struct TypeOf {};
57
58template <>
59struct TypeOf<boolean> {
60 static const TypeInfo* type();
61};
62
63template <>
64struct TypeOf<string> {
65 static const TypeInfo* type();
66};
67
68template <>
69struct TypeOf<integer> {
70 static const TypeInfo* type();
71};
72
73template <>
74struct TypeOf<number> {
75 static const TypeInfo* type();
76};
77
78template <>
79struct TypeOf<object> {
80 static const TypeInfo* type();
81};
82
83template <>
84struct TypeOf<any> {
85 static const TypeInfo* type();
86};
87
88template <>
89struct TypeOf<null> {
90 static const TypeInfo* type();
91};
92
93template <typename T>
94struct TypeOf<array<T>> {
95 static inline const TypeInfo* type() {
96 static auto typeinfo = TypeInfo::create<BasicTypeInfo<array<T>>>(
97 "array<" + TypeOf<T>::type()->name() + ">");
98 return typeinfo;
99 }
100};
101
102template <typename T0, typename... Types>
103struct TypeOf<variant<T0, Types...>> {
104 static inline const TypeInfo* type() {
105 static auto typeinfo =
106 TypeInfo::create<BasicTypeInfo<variant<T0, Types...>>>("variant");
107 return typeinfo;
108 }
109};
110
111template <typename T>
112struct TypeOf<optional<T>> {
113 static inline const TypeInfo* type() {
114 static auto typeinfo = TypeInfo::create<BasicTypeInfo<optional<T>>>(
115 "optional<" + TypeOf<T>::type()->name() + ">");
116 return typeinfo;
117 }
118};
119
120// DAP_OFFSETOF() macro is a generalization of the offsetof() macro defined in
121// <cstddef>. It evaluates to the offset of the given field, with fewer
122// restrictions than offsetof(). We cast the address '32' and subtract it again,
123// because null-dereference is undefined behavior.
124#define DAP_OFFSETOF(s, m) \
125 ((int)(size_t) & reinterpret_cast<const volatile char&>((((s*)32)->m)) - 32)
126
127// internal functionality
128namespace detail {
129template <class T, class M>
130M member_type(M T::*);
131} // namespace detail
132
133// DAP_TYPEOF() returns the type of the struct (s) member (m).
134#define DAP_TYPEOF(s, m) decltype(detail::member_type(&s::m))
135
136// DAP_FIELD() declares a structure field for the DAP_IMPLEMENT_STRUCT_TYPEINFO
137// macro.
138// FIELD is the name of the struct field.
139// NAME is the serialized name of the field, as described by the DAP
140// specification.
141#define DAP_FIELD(FIELD, NAME) \
142 ::dap::Field { \
143 NAME, DAP_OFFSETOF(StructTy, FIELD), \
144 TypeOf<DAP_TYPEOF(StructTy, FIELD)>::type(), \
145 }
146
147// DAP_DECLARE_STRUCT_TYPEINFO() declares a TypeOf<> specialization for STRUCT.
148// Must be used within the 'dap' namespace.
149#define DAP_DECLARE_STRUCT_TYPEINFO(STRUCT) \
150 template <> \
151 struct TypeOf<STRUCT> { \
152 static constexpr bool has_custom_serialization = true; \
153 static const TypeInfo* type(); \
154 static bool deserializeFields(const Deserializer*, void* obj); \
155 static bool serializeFields(FieldSerializer*, const void* obj); \
156 }
157
158// DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION() implements the deserializeFields()
159// and serializeFields() static methods of a TypeOf<> specialization. Used
160// internally by DAP_IMPLEMENT_STRUCT_TYPEINFO() and
161// DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT().
162// You probably do not want to use this directly.
163#define DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, ...) \
164 bool TypeOf<STRUCT>::deserializeFields(const Deserializer* d, void* obj) { \
165 using StructTy = STRUCT; \
166 (void)sizeof(StructTy); /* avoid unused 'using' warning */ \
167 for (auto field : std::initializer_list<Field>{__VA_ARGS__}) { \
168 if (!d->field(field.name, [&](Deserializer* d) { \
169 auto ptr = reinterpret_cast<uint8_t*>(obj) + field.offset; \
170 return field.type->deserialize(d, ptr); \
171 })) { \
172 return false; \
173 } \
174 } \
175 return true; \
176 } \
177 bool TypeOf<STRUCT>::serializeFields(FieldSerializer* s, const void* obj) { \
178 using StructTy = STRUCT; \
179 (void)sizeof(StructTy); /* avoid unused 'using' warning */ \
180 for (auto field : std::initializer_list<Field>{__VA_ARGS__}) { \
181 if (!s->field(field.name, [&](Serializer* s) { \
182 auto ptr = reinterpret_cast<const uint8_t*>(obj) + field.offset; \
183 return field.type->serialize(s, ptr); \
184 })) { \
185 return false; \
186 } \
187 } \
188 return true; \
189 }
190
191// DAP_IMPLEMENT_STRUCT_TYPEINFO() implements the type() member function for the
192// TypeOf<> specialization for STRUCT.
193// STRUCT is the structure typename.
194// NAME is the serialized name of the structure, as described by the DAP
195// specification. The variadic (...) parameters should be a repeated list of
196// DAP_FIELD()s, one for each field of the struct.
197// Must be used within the 'dap' namespace.
198#define DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, ...) \
199 DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, __VA_ARGS__) \
200 const ::dap::TypeInfo* TypeOf<STRUCT>::type() { \
201 struct TI : BasicTypeInfo<STRUCT> { \
202 TI() : BasicTypeInfo<STRUCT>(NAME) {} \
203 bool deserialize(const Deserializer* d, void* obj) const override { \
204 return deserializeFields(d, obj); \
205 } \
206 bool serialize(Serializer* s, const void* obj) const override { \
207 return s->object( \
208 [&](FieldSerializer* fs) { return serializeFields(fs, obj); }); \
209 } \
210 }; \
211 static TI typeinfo; \
212 return &typeinfo; \
213 }
214
215// DAP_STRUCT_TYPEINFO() is a helper for declaring and implementing a TypeOf<>
216// specialization for STRUCT in a single statement.
217// Must be used within the 'dap' namespace.
218#define DAP_STRUCT_TYPEINFO(STRUCT, NAME, ...) \
219 DAP_DECLARE_STRUCT_TYPEINFO(STRUCT); \
220 DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, __VA_ARGS__)
221
222// DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT() implements the type() member function for
223// the TypeOf<> specialization for STRUCT that derives from BASE.
224// STRUCT is the structure typename.
225// BASE is the base structure typename.
226// NAME is the serialized name of the structure, as described by the DAP
227// specification. The variadic (...) parameters should be a repeated list of
228// DAP_FIELD()s, one for each field of the struct.
229// Must be used within the 'dap' namespace.
230#define DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, ...) \
231 static_assert(std::is_base_of<BASE, STRUCT>::value, \
232 #STRUCT " does not derive from " #BASE); \
233 DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, __VA_ARGS__) \
234 const ::dap::TypeInfo* TypeOf<STRUCT>::type() { \
235 struct TI : BasicTypeInfo<STRUCT> { \
236 TI() : BasicTypeInfo<STRUCT>(NAME) {} \
237 bool deserialize(const Deserializer* d, void* obj) const override { \
238 auto derived = static_cast<STRUCT*>(obj); \
239 auto base = static_cast<BASE*>(obj); \
240 return TypeOf<BASE>::deserializeFields(d, base) && \
241 deserializeFields(d, derived); \
242 } \
243 bool serialize(Serializer* s, const void* obj) const override { \
244 return s->object([&](FieldSerializer* fs) { \
245 auto derived = static_cast<const STRUCT*>(obj); \
246 auto base = static_cast<const BASE*>(obj); \
247 return TypeOf<BASE>::serializeFields(fs, base) && \
248 serializeFields(fs, derived); \
249 }); \
250 } \
251 }; \
252 static TI typeinfo; \
253 return &typeinfo; \
254 }
255
256// DAP_STRUCT_TYPEINFO_EXT() is a helper for declaring and implementing a
257// TypeOf<> specialization for STRUCT that derives from BASE in a single
258// statement.
259// Must be used within the 'dap' namespace.
260#define DAP_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, ...) \
261 DAP_DECLARE_STRUCT_TYPEINFO(STRUCT); \
262 DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, __VA_ARGS__)
263
264} // namespace dap
265
266#endif // dap_typeof_h
267