// 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 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&) 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&) const = 0; // deserialize() delegates to TypeOf::type()->deserialize(). template ::has_custom_serialization>> inline bool deserialize(T*) const; // deserialize() decodes an array. template inline bool deserialize(dap::array*) const; // deserialize() decodes an optional. template inline bool deserialize(dap::optional*) const; // deserialize() decodes an variant. template inline bool deserialize(dap::variant*) const; // deserialize() decodes a list of fields and stores them into the object. inline bool deserialize(void* object, const std::initializer_list&) const; // deserialize() decodes the struct field f with the given name. template inline bool field(const std::string& name, T* f) const; }; template bool Deserializer::deserialize(T* ptr) const { return TypeOf::type()->deserialize(this, ptr); } template bool Deserializer::deserialize(dap::array* 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 bool Deserializer::deserialize(dap::optional* opt) const { T v; if (deserialize(&v)) { *opt = v; }; return true; } template bool Deserializer::deserialize(dap::variant* var) const { return deserialize(&var->value); } bool Deserializer::deserialize( void* object, const std::initializer_list& fields) const { for (auto const& f : fields) { if (!field(f.name, [&](Deserializer* d) { auto ptr = reinterpret_cast(object) + f.offset; return f.type->deserialize(d, ptr); })) { return false; } } return true; } template 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; template using IsFieldSerializer = std::is_convertible; // 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&) = 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::type()->serialize(). template ::has_custom_serialization>> inline bool serialize(const T&); // serialize() encodes the given array. template inline bool serialize(const dap::array&); // serialize() encodes the given optional. template inline bool serialize(const dap::optional& v); // serialize() encodes the given variant. template inline bool serialize(const dap::variant&); // serialize() encodes all the provided fields of the given object. inline bool serialize(const void* object, const std::initializer_list&); // 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::value>::type> inline bool field(const std::string& name, const T& v); }; template bool Serializer::serialize(const T& object) { return TypeOf::type()->serialize(this, &object); } template bool Serializer::serialize(const dap::array& vec) { auto it = vec.begin(); return array(vec.size(), [&](Serializer* s) { return s->serialize(*it++); }); } template bool Serializer::serialize(const dap::optional& opt) { if (!opt.has_value()) { remove(); return true; } return serialize(opt.value()); } template bool Serializer::serialize(const dap::variant& var) { return serialize(var.value); } bool Serializer::serialize(const void* object, const std::initializer_list& fields) { for (auto const& f : fields) { if (!field(f.name, [&](Serializer* d) { auto ptr = reinterpret_cast(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 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