mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-02 14:16:16 -04:00
Add automatic JSON serialization/deserialization
Abstract serialization concept to pure virtaul class RsSerializable from which every other serializable class must inherit from Use RapidJSON for JSON manipulation Add TO_JSON and FROM_JSON SerializeJob Deprecate unused SerializationFormat Remove some unused old piece of code Adjust many lines to max 80 columns for better readability on little screens Clean up documentation and code, remove old cruft Add copyright notice on edited files that miss it
This commit is contained in:
parent
49cacc41a1
commit
5cdc5aa58d
12 changed files with 1384 additions and 405 deletions
|
@ -238,8 +238,7 @@ uint32_t getRawStringSize(const std::string &outStr)
|
|||
|
||||
bool getRawString(const void *data, uint32_t size, uint32_t *offset, std::string &outStr)
|
||||
{
|
||||
#warning Gio: "I had to change this. It seems like a bug to not clear the string. Should make sure it's not introducing any side effect."
|
||||
outStr.clear();
|
||||
outStr.clear();
|
||||
|
||||
uint32_t len = 0;
|
||||
if (!getRawUInt32(data, size, offset, &len))
|
||||
|
|
137
libretroshare/src/serialiser/rsserializable.h
Normal file
137
libretroshare/src/serialiser/rsserializable.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
#pragma once
|
||||
/*
|
||||
* RetroShare Serialiser.
|
||||
* Copyright (C) 2016-2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "serialiser/rsserializer.h"
|
||||
|
||||
/** @brief Minimal ancestor for all serializable structs in RetroShare
|
||||
* If you want your struct to be easly serializable you should inherit from this
|
||||
* struct.
|
||||
*/
|
||||
struct RsSerializable
|
||||
{
|
||||
/** Register struct members to serialize in this method taking advantage of
|
||||
* the helper macros
|
||||
* @see RS_REGISTER_SERIAL_MEMBER(I)
|
||||
* @see RS_REGISTER_SERIAL_MEMBER_TYPED(I, T)
|
||||
* @see RS_REGISTER_SERIALIZABLE_TYPE(T)
|
||||
*/
|
||||
virtual void serial_process(RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx) = 0;
|
||||
};
|
||||
|
||||
|
||||
/** @def RS_REGISTER_SERIAL_MEMBER(I)
|
||||
* Use this macro to register the members of `YourSerializable` for serial
|
||||
* processing inside `YourSerializable::serial_process(j, ctx)`
|
||||
*
|
||||
* Inspired by http://stackoverflow.com/a/39345864
|
||||
*/
|
||||
#define RS_REGISTER_SERIAL_MEMBER(I) \
|
||||
do { RsTypeSerializer::serial_process(j, ctx, I, #I); } while(0)
|
||||
|
||||
|
||||
/** @def RS_REGISTER_SERIAL_MEMBER_TYPED(I, T)
|
||||
* This macro usage is similar to @see RS_REGISTER_SERIAL_MEMBER(I) but it
|
||||
* permit to force serialization/deserialization type, it is expecially useful
|
||||
* with enum class members or RsTlvItem derivative members, be very careful with
|
||||
* the type you pass, as reinterpret_cast on a reference is used that is
|
||||
* expecially permissive so you can shot your feet if not carefull enough.
|
||||
*
|
||||
* If you are using this with an RsSerializable derivative (so passing
|
||||
* RsSerializable as T) consider to register your item type with
|
||||
* @see RS_REGISTER_SERIALIZABLE_TYPE(T) in
|
||||
* association with @see RS_REGISTER_SERIAL_MEMBER(I) that rely on template
|
||||
* function generation, as in this particular case
|
||||
* RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) would cause the serial code rely on
|
||||
* C++ dynamic dispatching that may have a noticeable impact on runtime
|
||||
* performances.
|
||||
*/
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#define RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) do {\
|
||||
RsTypeSerializer::serial_process<T>(j, ctx, reinterpret_cast<T&>(I), #I);\
|
||||
} while(0)
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
|
||||
/** @def RS_REGISTER_SERIALIZABLE_TYPE(T)
|
||||
* Use this macro into `youritem.cc` only if you need to process members of
|
||||
* subtypes of RsSerializable.
|
||||
*
|
||||
* The usage of this macro is strictly needed only in some cases, for example if
|
||||
* you are registering for serialization a member of a container that contains
|
||||
* items of subclasses of RsSerializable like
|
||||
* `std::map<uint64_t, RsChatMsgItem>`
|
||||
*
|
||||
* @code{.cpp}
|
||||
struct PrivateOugoingMapItem : RsChatItem
|
||||
{
|
||||
PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {}
|
||||
|
||||
void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx );
|
||||
|
||||
std::map<uint64_t, RsChatMsgItem> store;
|
||||
};
|
||||
|
||||
RS_REGISTER_SERIALIZABLE_TYPE(RsChatMsgItem)
|
||||
|
||||
void PrivateOugoingMapItem::serial_process(
|
||||
RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
// store is of type
|
||||
RS_REGISTER_SERIAL_MEMBER(store);
|
||||
}
|
||||
* @endcode
|
||||
*
|
||||
* If you use this macro with a lot of different item types this can cause the
|
||||
* generated binary grow in size, consider the usage of
|
||||
* @see RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) passing RsSerializable as type in
|
||||
* that case.
|
||||
*/
|
||||
#define RS_REGISTER_SERIALIZABLE_TYPE_DEF(T) template<> /*static*/\
|
||||
void RsTypeSerializer::serial_process<T>( \
|
||||
RsGenericSerializer::SerializeJob j,\
|
||||
RsGenericSerializer::SerializeContext& ctx, T& item,\
|
||||
const std::string& objName ) \
|
||||
{ \
|
||||
RsTypeSerializer::serial_process<RsSerializable>( j, \
|
||||
ctx, static_cast<RsSerializable&>(item), objName ); \
|
||||
}
|
||||
|
||||
|
||||
/** @def RS_REGISTER_SERIALIZABLE_TYPE_DECL(T)
|
||||
* The usage of this macro into your header file is needed only in case you
|
||||
* needed @see RS_REGISTER_SERIALIZABLE_TYPE_DEF(T) in your definitions file,
|
||||
* but it was not enough and the compiler kept complanining about undefined
|
||||
* references to serialize, deserialize, serial_size, print_data, to_JSON,
|
||||
* from_JSON for your RsSerializable derrived type.
|
||||
*
|
||||
* One example of such case is RsIdentityUsage that is declared in
|
||||
* retroshare/rsidentity.h but defined in services/p3idservice.cc, also if
|
||||
* RS_REGISTER_SERIALIZABLE_TYPE_DEF(RsIdentityUsage) was used in p3idservice.cc
|
||||
* for some reason it was not enough for the compiler to see it so
|
||||
* RS_REGISTER_SERIALIZABLE_TYPE_DECL(RsIdentityUsage) has been added in
|
||||
* rsidentity.h too and now the compiler is happy.
|
||||
*/
|
||||
#define RS_REGISTER_SERIALIZABLE_TYPE_DECL(T) template<> /*static*/\
|
||||
void RsTypeSerializer::serial_process<T>( \
|
||||
RsGenericSerializer::SerializeJob j,\
|
||||
RsGenericSerializer::SerializeContext& ctx, T& item,\
|
||||
const std::string& /*objName*/ );
|
|
@ -3,7 +3,8 @@
|
|||
*
|
||||
* RetroShare Serialiser.
|
||||
*
|
||||
* Copyright 2016 by Cyril Soler
|
||||
* Copyright (C) 2016 Cyril Soler
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -153,9 +154,11 @@
|
|||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include "retroshare/rsflags.h"
|
||||
#include "serialiser/rsserial.h"
|
||||
#include "util/rsdeprecate.h"
|
||||
|
||||
class RsItem ;
|
||||
|
||||
|
@ -194,106 +197,125 @@ class RsRawSerialiser: public RsSerialType
|
|||
virtual RsItem * deserialise(void *data, uint32_t *size);
|
||||
};
|
||||
|
||||
// Top class for all services and config serializers.
|
||||
typedef rapidjson::Document RsJson;
|
||||
|
||||
class RsGenericSerializer: public RsSerialType
|
||||
/// Top class for all services and config serializers.
|
||||
struct RsGenericSerializer : RsSerialType
|
||||
{
|
||||
public:
|
||||
typedef enum { SIZE_ESTIMATE = 0x01, SERIALIZE = 0x02, DESERIALIZE = 0x03, PRINT=0x04 } SerializeJob ;
|
||||
typedef enum { FORMAT_BINARY = 0x01, FORMAT_JSON = 0x02 } SerializationFormat ;
|
||||
|
||||
class SerializeContext
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
SIZE_ESTIMATE = 0x01,
|
||||
SERIALIZE = 0x02,
|
||||
DESERIALIZE = 0x03,
|
||||
PRINT = 0x04,
|
||||
TO_JSON,
|
||||
FROM_JSON
|
||||
} SerializeJob;
|
||||
|
||||
|
||||
SerializeContext(uint8_t *data,uint32_t size,SerializationFormat format,SerializationFlags flags)
|
||||
: mData(data),mSize(size),mOffset(0),mOk(true),mFormat(format),mFlags(flags) {}
|
||||
/** @deprecated use SerializeJob instead */
|
||||
RS_DEPRECATED typedef enum
|
||||
{
|
||||
FORMAT_BINARY = 0x01,
|
||||
FORMAT_JSON = 0x02
|
||||
} SerializationFormat;
|
||||
|
||||
unsigned char *mData ;
|
||||
uint32_t mSize ;
|
||||
uint32_t mOffset ;
|
||||
bool mOk ;
|
||||
SerializationFormat mFormat ;
|
||||
SerializationFlags mFlags ;
|
||||
};
|
||||
struct SerializeContext
|
||||
{
|
||||
/** Allow shared allocator usage to avoid costly JSON deepcopy for
|
||||
* nested RsSerializable */
|
||||
SerializeContext(
|
||||
uint8_t *data, uint32_t size, SerializationFormat format,
|
||||
SerializationFlags flags,
|
||||
RsJson::AllocatorType* allocator = nullptr) :
|
||||
mData(data), mSize(size), mOffset(0), mOk(true), mFormat(format),
|
||||
mFlags(flags), mJson(rapidjson::kObjectType, allocator) {}
|
||||
|
||||
// These are convenience flags to be used by the items when processing the data. The names of the flags
|
||||
// are not very important. What matters is that the serial_process() method of each item correctly
|
||||
// deals with the data when it sees the flags, if the serialiser sets them. By default the flags are not
|
||||
// set and shouldn't be handled.
|
||||
// When deriving a new serializer, the user can set his own flags, using compatible values
|
||||
unsigned char *mData;
|
||||
uint32_t mSize;
|
||||
uint32_t mOffset;
|
||||
bool mOk;
|
||||
RS_DEPRECATED SerializationFormat mFormat;
|
||||
SerializationFlags mFlags;
|
||||
RsJson mJson;
|
||||
};
|
||||
|
||||
static const SerializationFlags SERIALIZATION_FLAG_NONE ; // 0x0000
|
||||
static const SerializationFlags SERIALIZATION_FLAG_CONFIG ; // 0x0001
|
||||
static const SerializationFlags SERIALIZATION_FLAG_SIGNATURE ; // 0x0002
|
||||
static const SerializationFlags SERIALIZATION_FLAG_SKIP_HEADER ; // 0x0004
|
||||
/** These are convenience flags to be used by the items when processing the
|
||||
* data. The names of the flags are not very important. What matters is that
|
||||
* the serial_process() method of each item correctly deals with the data
|
||||
* when it sees the flags, if the serialiser sets them.
|
||||
* By default the flags are not set and shouldn't be handled.
|
||||
* When deriving a new serializer, the user can set his own flags, using
|
||||
* compatible values
|
||||
*/
|
||||
static const SerializationFlags SERIALIZATION_FLAG_NONE; // 0x0000
|
||||
static const SerializationFlags SERIALIZATION_FLAG_CONFIG; // 0x0001
|
||||
static const SerializationFlags SERIALIZATION_FLAG_SIGNATURE; // 0x0002
|
||||
static const SerializationFlags SERIALIZATION_FLAG_SKIP_HEADER; // 0x0004
|
||||
|
||||
// The following functions overload RsSerialType. They *should not* need to be further overloaded.
|
||||
|
||||
RsItem *deserialise(void *data,uint32_t *size) =0;
|
||||
bool serialise(RsItem *item,void *data,uint32_t *size) ;
|
||||
uint32_t size(RsItem *item) ;
|
||||
void print(RsItem *item) ;
|
||||
/**
|
||||
* The following functions overload RsSerialType.
|
||||
* They *should not* need to be further overloaded.
|
||||
*/
|
||||
RsItem *deserialise(void *data,uint32_t *size) = 0;
|
||||
bool serialise(RsItem *item,void *data,uint32_t *size);
|
||||
uint32_t size(RsItem *item);
|
||||
void print(RsItem *item);
|
||||
|
||||
protected:
|
||||
RsGenericSerializer(uint8_t serial_class,
|
||||
uint8_t serial_type,
|
||||
SerializationFormat format,
|
||||
SerializationFlags flags )
|
||||
: RsSerialType(RS_PKT_VERSION1,serial_class,serial_type), mFormat(format),mFlags(flags)
|
||||
{}
|
||||
RsGenericSerializer(
|
||||
uint8_t serial_class, uint8_t serial_type,
|
||||
SerializationFormat format, SerializationFlags flags ) :
|
||||
RsSerialType( RS_PKT_VERSION1, serial_class, serial_type),
|
||||
mFormat(format), mFlags(flags) {}
|
||||
|
||||
RsGenericSerializer(uint16_t service,
|
||||
SerializationFormat format,
|
||||
SerializationFlags flags )
|
||||
: RsSerialType(RS_PKT_VERSION_SERVICE,service), mFormat(format),mFlags(flags)
|
||||
{}
|
||||
|
||||
SerializationFormat mFormat ;
|
||||
SerializationFlags mFlags ;
|
||||
RsGenericSerializer(
|
||||
uint16_t service, SerializationFormat format,
|
||||
SerializationFlags flags ) :
|
||||
RsSerialType( RS_PKT_VERSION_SERVICE, service ), mFormat(format),
|
||||
mFlags(flags) {}
|
||||
|
||||
SerializationFormat mFormat;
|
||||
SerializationFlags mFlags;
|
||||
};
|
||||
|
||||
// Top class for service serializers. Derive your on service serializer from this class and overload creat_item().
|
||||
|
||||
class RsServiceSerializer: public RsGenericSerializer
|
||||
/** Top class for service serializers.
|
||||
* Derive your on service serializer from this class and overload creat_item().
|
||||
*/
|
||||
struct RsServiceSerializer : RsGenericSerializer
|
||||
{
|
||||
public:
|
||||
RsServiceSerializer(uint16_t service_id,
|
||||
SerializationFormat format = FORMAT_BINARY,
|
||||
SerializationFlags flags = SERIALIZATION_FLAG_NONE)
|
||||
RsServiceSerializer(
|
||||
uint16_t service_id, SerializationFormat format = FORMAT_BINARY,
|
||||
SerializationFlags flags = SERIALIZATION_FLAG_NONE ) :
|
||||
RsGenericSerializer(service_id, format, flags) {}
|
||||
|
||||
: RsGenericSerializer(service_id,format,flags) {}
|
||||
/*! should be overloaded to create the correct type of item depending on the
|
||||
* data */
|
||||
virtual RsItem *create_item( uint16_t /* service */,
|
||||
uint8_t /* item_sub_id */ ) const = 0;
|
||||
|
||||
/*! create_item
|
||||
* should be overloaded to create the correct type of item depending on the data
|
||||
*/
|
||||
virtual RsItem *create_item(uint16_t /* service */, uint8_t /* item_sub_id */) const=0;
|
||||
|
||||
RsItem *deserialise(void *data,uint32_t *size) ;
|
||||
RsItem *deserialise(void *data, uint32_t *size);
|
||||
};
|
||||
|
||||
// Top class for config serializers. Config serializers are only used internally by RS core. The development of new services or plugins do not need this.
|
||||
|
||||
class RsConfigSerializer: public RsGenericSerializer
|
||||
/** Top class for config serializers.
|
||||
* Config serializers are only used internally by RS core.
|
||||
* The development of new services or plugins do not need this.
|
||||
*/
|
||||
struct RsConfigSerializer : RsGenericSerializer
|
||||
{
|
||||
public:
|
||||
RsConfigSerializer(uint8_t config_class,
|
||||
uint8_t config_type,
|
||||
SerializationFormat format = FORMAT_BINARY,
|
||||
SerializationFlags flags = SERIALIZATION_FLAG_NONE)
|
||||
SerializationFlags flags = SERIALIZATION_FLAG_NONE) :
|
||||
RsGenericSerializer(config_class,config_type,format,flags) {}
|
||||
|
||||
: RsGenericSerializer(config_class,config_type,format,flags) {}
|
||||
/*! should be overloaded to create the correct type of item depending on the
|
||||
* data */
|
||||
virtual RsItem *create_item(uint8_t /* item_type */,
|
||||
uint8_t /* item_sub_type */) const = 0;
|
||||
|
||||
/*! create_item
|
||||
* should be overloaded to create the correct type of item depending on the data
|
||||
*/
|
||||
virtual RsItem *create_item(uint8_t /* item_type */, uint8_t /* item_sub_type */) const=0;
|
||||
|
||||
RsItem *deserialise(void *data,uint32_t *size) ;
|
||||
RsItem *deserialise(void *data,uint32_t *size);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
*
|
||||
* RetroShare Serialiser.
|
||||
*
|
||||
* Copyright 2017 by Cyril Soler
|
||||
* Copyright (C) 2017 Cyril Soler
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -26,27 +27,48 @@
|
|||
#include "serialiser/rstypeserializer.h"
|
||||
#include "serialiser/rsbaseserial.h"
|
||||
#include "serialiser/rstlvkeys.h"
|
||||
|
||||
#include "rsitems/rsitem.h"
|
||||
#include "serialiser/rsserializable.h"
|
||||
|
||||
#include "util/rsprint.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <typeinfo>
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <typeinfo> // for typeid
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
|
||||
//static const uint32_t MAX_SERIALIZED_ARRAY_SIZE = 500 ;
|
||||
static const uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB.
|
||||
|
||||
//=================================================================================================//
|
||||
// Integer types //
|
||||
//=================================================================================================//
|
||||
#define SAFE_GET_JSON_V() \
|
||||
const char* mName = memberName.c_str(); \
|
||||
bool ret = jVal.HasMember(mName); \
|
||||
if(!ret) \
|
||||
{ \
|
||||
std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName \
|
||||
<< "\" not found in JSON:" << std::endl \
|
||||
<< jVal << std::endl << std::endl; \
|
||||
print_stacktrace(); \
|
||||
return false; \
|
||||
} \
|
||||
rapidjson::Value& v = jVal[mName]
|
||||
|
||||
//============================================================================//
|
||||
// Integer types //
|
||||
//============================================================================//
|
||||
|
||||
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const bool& member)
|
||||
{
|
||||
return setRawUInt8(data,size,&offset,member);
|
||||
}
|
||||
template<> bool RsTypeSerializer::serialize(uint8_t /*data*/[], uint32_t /*size*/, uint32_t& /*offset*/, const int32_t& /*member*/)
|
||||
{
|
||||
// TODO: nice to have but not used ATM
|
||||
return false;
|
||||
}
|
||||
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset, const uint8_t& member)
|
||||
{
|
||||
return setRawUInt8(data,size,&offset,member);
|
||||
|
@ -70,10 +92,15 @@ template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint3
|
|||
|
||||
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, bool& member)
|
||||
{
|
||||
uint8_t m ;
|
||||
uint8_t m;
|
||||
bool ok = getRawUInt8(data,size,&offset,&m);
|
||||
member = m ;
|
||||
return ok;
|
||||
member = m;
|
||||
return ok;
|
||||
}
|
||||
template<> bool RsTypeSerializer::deserialize(const uint8_t /*data*/[], uint32_t /*size*/, uint32_t& /*offset*/, int32_t& /*member*/)
|
||||
{
|
||||
// TODO: nice to have but not used ATM
|
||||
return false;
|
||||
}
|
||||
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size, uint32_t &offset, uint8_t& member)
|
||||
{
|
||||
|
@ -100,6 +127,10 @@ template<> uint32_t RsTypeSerializer::serial_size(const bool& /* member*/)
|
|||
{
|
||||
return 1;
|
||||
}
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const int32_t& /* member*/)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const uint8_t& /* member*/)
|
||||
{
|
||||
return 1;
|
||||
|
@ -125,6 +156,10 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const bool &
|
|||
{
|
||||
std::cerr << " [bool ] " << n << ": " << V << std::endl;
|
||||
}
|
||||
template<> void RsTypeSerializer::print_data(const std::string& n, const int32_t& V)
|
||||
{
|
||||
std::cerr << " [int32_t ] " << n << ": " << V << std::endl;
|
||||
}
|
||||
template<> void RsTypeSerializer::print_data(const std::string& n, const uint8_t & V)
|
||||
{
|
||||
std::cerr << " [uint8_t ] " << n << ": " << V << std::endl;
|
||||
|
@ -146,10 +181,104 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const time_t&
|
|||
std::cerr << " [time_t ] " << n << ": " << V << " (" << time(NULL)-V << " secs ago)" << std::endl;
|
||||
}
|
||||
|
||||
#define SIMPLE_TO_JSON_DEF(T) \
|
||||
template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \
|
||||
const T& member, RsJson& jDoc ) \
|
||||
{ \
|
||||
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); \
|
||||
\
|
||||
rapidjson::Value key; \
|
||||
key.SetString(memberName.c_str(), memberName.length(), allocator); \
|
||||
\
|
||||
rapidjson::Value value(member); \
|
||||
\
|
||||
jDoc.AddMember(key, value, allocator); \
|
||||
\
|
||||
return true; \
|
||||
}
|
||||
|
||||
//=================================================================================================//
|
||||
// FLoats //
|
||||
//=================================================================================================//
|
||||
SIMPLE_TO_JSON_DEF(bool)
|
||||
SIMPLE_TO_JSON_DEF(int32_t)
|
||||
SIMPLE_TO_JSON_DEF(time_t)
|
||||
SIMPLE_TO_JSON_DEF(uint8_t)
|
||||
SIMPLE_TO_JSON_DEF(uint16_t)
|
||||
SIMPLE_TO_JSON_DEF(uint32_t)
|
||||
SIMPLE_TO_JSON_DEF(uint64_t)
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName, bool& member,
|
||||
RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsBool();
|
||||
if(ret) member = v.GetBool();
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
int32_t& member, RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsInt();
|
||||
if(ret) member = v.GetInt();
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName, time_t& member,
|
||||
RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsUint();
|
||||
if(ret) member = v.GetUint();
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
uint8_t& member, RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsUint();
|
||||
if(ret) member = v.GetUint();
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
uint16_t& member, RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsUint();
|
||||
if(ret) member = v.GetUint();
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
uint32_t& member, RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsUint();
|
||||
if(ret) member = v.GetUint();
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
uint64_t& member, RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsUint();
|
||||
if(ret) member = v.GetUint();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================//
|
||||
// FLoats //
|
||||
//============================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const float&){ return 4; }
|
||||
|
||||
|
@ -166,10 +295,75 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const float&
|
|||
std::cerr << " [float ] " << n << ": " << V << std::endl;
|
||||
}
|
||||
|
||||
SIMPLE_TO_JSON_DEF(float)
|
||||
|
||||
//=================================================================================================//
|
||||
// TlvString with subtype //
|
||||
//=================================================================================================//
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
float& member, RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsFloat();
|
||||
if(ret) member = v.GetFloat();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================//
|
||||
// std::string //
|
||||
//============================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const std::string& str)
|
||||
{
|
||||
return getRawStringSize(str);
|
||||
}
|
||||
template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size,
|
||||
uint32_t& offset,
|
||||
const std::string& str )
|
||||
{
|
||||
return setRawString(data, size, &offset, str);
|
||||
}
|
||||
template<> bool RsTypeSerializer::deserialize( const uint8_t data[],
|
||||
uint32_t size, uint32_t &offset,
|
||||
std::string& str )
|
||||
{
|
||||
return getRawString(data, size, &offset, str);
|
||||
}
|
||||
template<> void RsTypeSerializer::print_data( const std::string& n,
|
||||
const std::string& str )
|
||||
{
|
||||
std::cerr << " [std::string] " << n << ": " << str << std::endl;
|
||||
}
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::to_JSON( const std::string& membername,
|
||||
const std::string& member, RsJson& jDoc )
|
||||
{
|
||||
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator();
|
||||
|
||||
rapidjson::Value key;
|
||||
key.SetString(membername.c_str(), membername.length(), allocator);
|
||||
|
||||
rapidjson::Value value;;
|
||||
value.SetString(member.c_str(), member.length(), allocator);
|
||||
|
||||
jDoc.AddMember(key, value, allocator);
|
||||
|
||||
return true;
|
||||
}
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
std::string& member, RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
ret = ret && v.IsString();
|
||||
if(ret) member = v.GetString();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================================================================//
|
||||
// TlvString with subtype //
|
||||
//============================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size(uint16_t /* type_subtype */,const std::string& s)
|
||||
{
|
||||
|
@ -188,46 +382,130 @@ template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t siz
|
|||
|
||||
template<> void RsTypeSerializer::print_data(const std::string& n, uint16_t type_substring,const std::string& V)
|
||||
{
|
||||
std::cerr << " [TlvString ] " << n << ": type=" << std::hex <<std::setw(4)<<std::setfill('0') << type_substring << std::dec << " s=\"" << V<< "\"" << std::endl;
|
||||
std::cerr << " [TlvString ] " << n << ": type=" << std::hex <<std::setw(4)<<std::setfill('0') << type_substring << std::dec << " s=\"" << V<< "\"" << std::endl;
|
||||
}
|
||||
|
||||
//=================================================================================================//
|
||||
// TlvInt with subtype //
|
||||
//=================================================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size(uint16_t /* type_subtype */,const uint32_t& /*s*/)
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::to_JSON( const std::string& memberName,
|
||||
uint16_t /*sub_type*/,
|
||||
const std::string& member, RsJson& jDoc )
|
||||
{
|
||||
return GetTlvUInt32Size() ;
|
||||
return to_JSON<std::string>(memberName, member, jDoc);
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset,uint16_t sub_type,const uint32_t& s)
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
uint16_t /*sub_type*/,
|
||||
std::string& member, RsJson& jVal )
|
||||
{
|
||||
return SetTlvUInt32(data,size,&offset,sub_type,s) ;
|
||||
return from_JSON<std::string>(memberName, member, jVal);
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size,uint32_t& offset,uint16_t sub_type,uint32_t& s)
|
||||
//============================================================================//
|
||||
// TlvInt with subtype //
|
||||
//============================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size( uint16_t /* type_subtype */,
|
||||
const uint32_t& /*s*/ )
|
||||
{
|
||||
return GetTlvUInt32((void*)data,size,&offset,sub_type,&s) ;
|
||||
return GetTlvUInt32Size();
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size,
|
||||
uint32_t &offset,uint16_t sub_type,
|
||||
const uint32_t& s)
|
||||
{
|
||||
return SetTlvUInt32(data,size,&offset,sub_type,s);
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::deserialize( const uint8_t data[],
|
||||
uint32_t size, uint32_t& offset,
|
||||
uint16_t sub_type, uint32_t& s)
|
||||
{
|
||||
return GetTlvUInt32((void*)data, size, &offset, sub_type, &s);
|
||||
}
|
||||
|
||||
template<> void RsTypeSerializer::print_data(const std::string& n, uint16_t sub_type,const uint32_t& V)
|
||||
{
|
||||
std::cerr << " [TlvUInt32 ] " << n << ": type=" << std::hex <<std::setw(4)<<std::setfill('0') << sub_type << std::dec << " s=\"" << V<< "\"" << std::endl;
|
||||
std::cerr << " [TlvUInt32 ] " << n << ": type=" << std::hex
|
||||
<< std::setw(4) << std::setfill('0') << sub_type << std::dec
|
||||
<< " s=\"" << V << "\"" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
//=================================================================================================//
|
||||
// std::string //
|
||||
//=================================================================================================//
|
||||
|
||||
template<> void RsTypeSerializer::print_data(const std::string& n, const std::string& V)
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::to_JSON( const std::string& memberName,
|
||||
uint16_t /*sub_type*/,
|
||||
const uint32_t& member, RsJson& jDoc )
|
||||
{
|
||||
std::cerr << " [std::string] " << n << ": " << V << std::endl;
|
||||
return to_JSON<uint32_t>(memberName, member, jDoc);
|
||||
}
|
||||
|
||||
//=================================================================================================//
|
||||
// Binary blocks //
|
||||
//=================================================================================================//
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
uint16_t /*sub_type*/,
|
||||
uint32_t& member, RsJson& jVal )
|
||||
{
|
||||
return from_JSON<uint32_t>(memberName, member, jVal);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================//
|
||||
// TlvItems //
|
||||
//============================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const RsTlvItem& s)
|
||||
{
|
||||
return s.TlvSize();
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size,
|
||||
uint32_t &offset,const RsTlvItem& s)
|
||||
{
|
||||
return s.SetTlv(data,size,&offset);
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::deserialize(const uint8_t data[],
|
||||
uint32_t size,uint32_t& offset,
|
||||
RsTlvItem& s)
|
||||
{
|
||||
return s.GetTlv((void*)data,size,&offset) ;
|
||||
}
|
||||
|
||||
template<> void RsTypeSerializer::print_data( const std::string& n,
|
||||
const RsTlvItem& s )
|
||||
{
|
||||
std::cerr << " [" << typeid(s).name() << "] " << n << std::endl;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::to_JSON( const std::string& memberName,
|
||||
const RsTlvItem& member, RsJson& jDoc )
|
||||
{
|
||||
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator();
|
||||
|
||||
rapidjson::Value key;
|
||||
key.SetString(memberName.c_str(), memberName.length(), allocator);
|
||||
|
||||
rapidjson::Value value;
|
||||
const char* tName = typeid(member).name();
|
||||
value.SetString(tName, allocator);
|
||||
|
||||
jDoc.AddMember(key, value, allocator);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& /*memberName*/,
|
||||
RsTlvItem& /*member*/, RsJson& /*jVal*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================//
|
||||
// Binary blocks //
|
||||
//============================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const RsTypeSerializer::TlvMemBlock_proxy& r) { return 4 + r.second ; }
|
||||
|
||||
|
@ -286,82 +564,141 @@ template<> void RsTypeSerializer::print_data(const std::string& n, const RsTypeS
|
|||
std::cerr << " [Binary data] " << n << ", length=" << s.second << " data=" << RsUtil::BinToHex((uint8_t*)s.first,std::min(50u,s.second)) << ((s.second>50)?"...":"") << std::endl;
|
||||
}
|
||||
|
||||
//=================================================================================================//
|
||||
// TlvItems //
|
||||
//=================================================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const RsTlvItem& s)
|
||||
{
|
||||
return s.TlvSize() ;
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::serialize(uint8_t data[], uint32_t size, uint32_t &offset,const RsTlvItem& s)
|
||||
{
|
||||
return s.SetTlv(data,size,&offset) ;
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::deserialize(const uint8_t data[], uint32_t size,uint32_t& offset,RsTlvItem& s)
|
||||
{
|
||||
return s.GetTlv((void*)data,size,&offset) ;
|
||||
}
|
||||
|
||||
template<> void RsTypeSerializer::print_data(const std::string& n, const RsTlvItem& s)
|
||||
{
|
||||
// can we call TlvPrint inside this?
|
||||
|
||||
std::cerr << " [" << typeid(s).name() << "] " << n << std::endl;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
// RsItem and derivated //
|
||||
// RsSerializable and derivated //
|
||||
//============================================================================//
|
||||
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const RsItem& s)
|
||||
template<> uint32_t RsTypeSerializer::serial_size(const RsSerializable& s)
|
||||
{
|
||||
RsGenericSerializer::SerializeContext ctx(
|
||||
NULL, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE );
|
||||
|
||||
ctx.mOffset = 8; // header size
|
||||
const_cast<RsItem&>(s).serial_process(RsGenericSerializer::SIZE_ESTIMATE,
|
||||
ctx);
|
||||
const_cast<RsSerializable&>(s).serial_process(
|
||||
RsGenericSerializer::SIZE_ESTIMATE, ctx );
|
||||
|
||||
return ctx.mOffset;
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size,
|
||||
uint32_t &offset, const RsItem& s )
|
||||
uint32_t &offset,
|
||||
const RsSerializable& s )
|
||||
{
|
||||
RsGenericSerializer::SerializeContext ctx(
|
||||
data, size, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE );
|
||||
ctx.mOffset = offset;
|
||||
const_cast<RsItem&>(s).serial_process(RsGenericSerializer::SERIALIZE,
|
||||
ctx);
|
||||
const_cast<RsSerializable&>(s).serial_process(
|
||||
RsGenericSerializer::SERIALIZE, ctx );
|
||||
return true;
|
||||
}
|
||||
|
||||
template<> bool RsTypeSerializer::deserialize( const uint8_t data[],
|
||||
uint32_t size, uint32_t& offset,
|
||||
RsItem& s )
|
||||
RsSerializable& s )
|
||||
{
|
||||
RsGenericSerializer::SerializeContext ctx(
|
||||
const_cast<uint8_t*>(data), size,
|
||||
RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE );
|
||||
ctx.mOffset = offset;
|
||||
const_cast<RsItem&>(s).serial_process(RsGenericSerializer::DESERIALIZE,
|
||||
ctx);
|
||||
const_cast<RsSerializable&>(s).serial_process(
|
||||
RsGenericSerializer::DESERIALIZE, ctx );
|
||||
return true;
|
||||
}
|
||||
|
||||
template<> void RsTypeSerializer::print_data( const std::string& /*n*/,
|
||||
const RsItem& s )
|
||||
const RsSerializable& s )
|
||||
{
|
||||
RsGenericSerializer::SerializeContext ctx(
|
||||
NULL, 0,
|
||||
RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE );
|
||||
const_cast<RsItem&>(s).serial_process(RsGenericSerializer::PRINT,
|
||||
ctx);
|
||||
const_cast<RsSerializable&>(s).serial_process( RsGenericSerializer::PRINT,
|
||||
ctx );
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::to_JSON( const std::string& memberName,
|
||||
const RsSerializable& member, RsJson& jDoc )
|
||||
{
|
||||
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator();
|
||||
|
||||
// Reuse allocator to avoid deep copy later
|
||||
RsGenericSerializer::SerializeContext ctx(
|
||||
NULL, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
|
||||
const_cast<RsSerializable&>(member).serial_process(
|
||||
RsGenericSerializer::TO_JSON, ctx );
|
||||
|
||||
rapidjson::Value key;
|
||||
key.SetString(memberName.c_str(), memberName.length(), allocator);
|
||||
|
||||
/* Because the passed allocator is reused it doesn't go out of scope and
|
||||
* there is no need of deep copy and we can take advantage of the much
|
||||
* faster rapidjson move semantic */
|
||||
jDoc.AddMember(key, ctx.mJson, allocator);
|
||||
|
||||
return ctx.mOk;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
RsSerializable& member, RsJson& jVal )
|
||||
{
|
||||
SAFE_GET_JSON_V();
|
||||
|
||||
if(ret)
|
||||
{
|
||||
RsGenericSerializer::SerializeContext ctx(
|
||||
NULL, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE );
|
||||
|
||||
ctx.mJson.SetObject() = v; // Beware of move semantic!!
|
||||
member.serial_process(RsGenericSerializer::FROM_JSON, ctx);
|
||||
ret = ret && ctx.mOk;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<> /*static*/
|
||||
void RsTypeSerializer::serial_process<RsSerializable>(
|
||||
RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx, RsSerializable& object,
|
||||
const std::string& objName )
|
||||
{
|
||||
switch (j)
|
||||
{
|
||||
case RsGenericSerializer::SIZE_ESTIMATE: // fall-through
|
||||
case RsGenericSerializer::SERIALIZE: // fall-through
|
||||
case RsGenericSerializer::DESERIALIZE: // fall-through
|
||||
case RsGenericSerializer::PRINT: // fall-through
|
||||
object.serial_process(j, ctx);
|
||||
break;
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
ctx.mOk = ctx.mOk && to_JSON(objName, object, ctx.mJson);
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
ctx.mOk = ctx.mOk && from_JSON(objName, object, ctx.mJson);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================//
|
||||
// RsJson std:ostream support //
|
||||
//============================================================================//
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const RsJson &jDoc)
|
||||
{
|
||||
rapidjson::StringBuffer buffer; buffer.Clear();
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
||||
jDoc.Accept(writer);
|
||||
return out << buffer.GetString();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
*
|
||||
* RetroShare Serialiser.
|
||||
*
|
||||
* Copyright 2017 by Cyril Soler
|
||||
* Copyright (C) 2017 Cyril Soler
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -32,83 +33,91 @@
|
|||
#include "retroshare/rsids.h"
|
||||
|
||||
#include "serialiser/rsserializer.h"
|
||||
#include "serialiser/rsserializable.h"
|
||||
|
||||
/** @def RS_REGISTER_SERIAL_MEMBER(I)
|
||||
* Use this macro to register the members of `YourItem` for serial processing
|
||||
* inside `YourItem::serial_process(j, ctx)`
|
||||
*
|
||||
* Inspired by http://stackoverflow.com/a/39345864
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
/** INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set}<T>
|
||||
* Can't use a template function because T is needed for const_cast */
|
||||
#define RsTypeSerializer_PRIVATE_TO_JSON_ARRAY() do \
|
||||
{ \
|
||||
using namespace rapidjson; \
|
||||
\
|
||||
Document::AllocatorType& allocator = ctx.mJson.GetAllocator(); \
|
||||
\
|
||||
Value arrKey; arrKey.SetString(memberName.c_str(), allocator); \
|
||||
\
|
||||
Value arr(kArrayType); \
|
||||
\
|
||||
for (auto& el : v) \
|
||||
{ \
|
||||
/* Use same allocator to avoid deep copy */\
|
||||
RsGenericSerializer::SerializeContext elCtx(\
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,\
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,\
|
||||
&allocator );\
|
||||
\
|
||||
/* If el is const the default serial_process template is matched */ \
|
||||
/* also when specialization is necessary so the compilation break */ \
|
||||
serial_process(j, elCtx, const_cast<T&>(el), memberName); \
|
||||
\
|
||||
elCtx.mOk = elCtx.mOk && elCtx.mJson.HasMember(arrKey);\
|
||||
if(elCtx.mOk) arr.PushBack(elCtx.mJson[arrKey], allocator);\
|
||||
else\
|
||||
{\
|
||||
ctx.mOk = false;\
|
||||
break;\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
ctx.mJson.AddMember(arrKey, arr, allocator);\
|
||||
} while (false)
|
||||
|
||||
/** INTERNAL ONLY helper to avoid copy paste code for std::{vector,list,set}<T>
|
||||
* Can't use a template function because std::{vector,list,set}<T> has different
|
||||
* name for insert/push_back function
|
||||
*/
|
||||
#define RS_REGISTER_SERIAL_MEMBER(I) \
|
||||
do { RsTypeSerializer::serial_process(j, ctx, I, #I); } while(0)
|
||||
#define RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(INSERT_FUN) do\
|
||||
{\
|
||||
using namespace rapidjson;\
|
||||
\
|
||||
bool& ok(ctx.mOk);\
|
||||
Document& jDoc(ctx.mJson);\
|
||||
Document::AllocatorType& allocator = jDoc.GetAllocator();\
|
||||
\
|
||||
Value arrKey;\
|
||||
arrKey.SetString(memberName.c_str(), memberName.length());\
|
||||
\
|
||||
ok = ok && jDoc.IsObject();\
|
||||
ok = ok && jDoc.HasMember(arrKey);\
|
||||
\
|
||||
if(ok && jDoc[arrKey].IsArray())\
|
||||
{\
|
||||
for (auto&& arrEl : jDoc[arrKey].GetArray())\
|
||||
{\
|
||||
RsGenericSerializer::SerializeContext elCtx(\
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,\
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,\
|
||||
&allocator );\
|
||||
elCtx.mJson.AddMember(arrKey, arrEl, allocator);\
|
||||
\
|
||||
T el;\
|
||||
serial_process(j, elCtx, el, memberName); \
|
||||
ok = ok && elCtx.mOk;\
|
||||
\
|
||||
if(ok) v.INSERT_FUN(el);\
|
||||
else break;\
|
||||
}\
|
||||
}\
|
||||
} while(false)
|
||||
|
||||
/** @def RS_REGISTER_SERIAL_MEMBER_TYPED(I, T)
|
||||
* This macro usage is similar to @see RS_REGISTER_SERIAL_MEMBER(I) but it
|
||||
* permit to force serialization/deserialization type, it is expecially useful
|
||||
* with enum class members or RsTlvItem derivative members, be very careful with
|
||||
* the type you pass, as reinterpret_cast on a reference is used that is
|
||||
* expecially permissive so you can shot your feet if not carefull enough.
|
||||
*
|
||||
* If you are using this with an RsItem derivative (so passing RsItem as T)
|
||||
* consider to register your item type with @see RS_REGISTER_ITEM_TYPE(T) in
|
||||
* association with @see RS_REGISTER_SERIAL_MEMBER(I) that rely on template
|
||||
* function generation, as in this particular case
|
||||
* RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) would cause the serial code rely on
|
||||
* C++ dynamic dispatching that may have a noticeable impact on runtime
|
||||
* performances.
|
||||
*/
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#define RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) do {\
|
||||
RsTypeSerializer::serial_process<T>(j, ctx, reinterpret_cast<T&>(I), #I);\
|
||||
} while(0)
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
/** @def RS_REGISTER_ITEM_TYPE(T)
|
||||
* Use this macro into `youritem.cc` only if you need to process members of
|
||||
* subtypes of RsItem.
|
||||
*
|
||||
* The usage of this macro is strictly needed only in some cases, for example if
|
||||
* you are registering for serialization a member of a container that contains
|
||||
* items of subclasses of RsItem like * `std::map<uint64_t, RsChatMsgItem>`
|
||||
*
|
||||
* @code{.cpp}
|
||||
struct PrivateOugoingMapItem : RsChatItem
|
||||
{
|
||||
PrivateOugoingMapItem() : RsChatItem(RS_PKT_SUBTYPE_OUTGOING_MAP) {}
|
||||
|
||||
void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx );
|
||||
|
||||
std::map<uint64_t, RsChatMsgItem> store;
|
||||
};
|
||||
|
||||
RS_REGISTER_ITEM_TYPE(RsChatMsgItem)
|
||||
|
||||
void PrivateOugoingMapItem::serial_process(
|
||||
RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
// store is of type
|
||||
RS_REGISTER_SERIAL_MEMBER(store);
|
||||
}
|
||||
* @endcode
|
||||
*
|
||||
* If you use this macro with a lot of different item types this can cause the
|
||||
* generated binary grow in size, consider the usage of
|
||||
* @see RS_REGISTER_SERIAL_MEMBER_TYPED(I, T) passing RsItem as type in that
|
||||
* case.
|
||||
*/
|
||||
#define RS_REGISTER_ITEM_TYPE(T) template<> \
|
||||
void RsTypeSerializer::serial_process<T>( \
|
||||
RsGenericSerializer::SerializeJob j,\
|
||||
RsGenericSerializer::SerializeContext& ctx, T& item,\
|
||||
const std::string& /*name*/) { item.serial_process(j, ctx); }
|
||||
std::ostream &operator<<(std::ostream &out, const RsJson &jDoc);
|
||||
|
||||
struct RsTypeSerializer
|
||||
{
|
||||
/** This type should be used to pass a parameter to drive the serialisation
|
||||
* if needed */
|
||||
struct TlvMemBlock_proxy: public std::pair<void*&,uint32_t&>
|
||||
struct TlvMemBlock_proxy : std::pair<void*&,uint32_t&>
|
||||
{
|
||||
TlvMemBlock_proxy(void*& p, uint32_t& s) :
|
||||
std::pair<void*&,uint32_t&>(p,s) {}
|
||||
|
@ -120,7 +129,7 @@ struct RsTypeSerializer
|
|||
template<typename T>
|
||||
static void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
T& member,const std::string& member_name)
|
||||
T& member, const std::string& member_name )
|
||||
{
|
||||
switch(j)
|
||||
{
|
||||
|
@ -138,6 +147,12 @@ struct RsTypeSerializer
|
|||
case RsGenericSerializer::PRINT:
|
||||
print_data(member_name,member);
|
||||
break;
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
ctx.mOk = ctx.mOk && to_JSON(member_name, member, ctx.mJson);
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
ctx.mOk = ctx.mOk && from_JSON(member_name, member, ctx.mJson);
|
||||
break;
|
||||
default:
|
||||
ctx.mOk = false;
|
||||
throw std::runtime_error("Unknown serial job");
|
||||
|
@ -165,7 +180,15 @@ struct RsTypeSerializer
|
|||
serialize(ctx.mData,ctx.mSize,ctx.mOffset,type_id,member);
|
||||
break;
|
||||
case RsGenericSerializer::PRINT:
|
||||
print_data(member_name,type_id,member);
|
||||
print_data(member_name, member);
|
||||
break;
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
ctx.mOk = ctx.mOk &&
|
||||
to_JSON(member_name, type_id, member, ctx.mJson);
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
ctx.mOk = ctx.mOk &&
|
||||
from_JSON(member_name, type_id, member, ctx.mJson);
|
||||
break;
|
||||
default:
|
||||
ctx.mOk = false;
|
||||
|
@ -178,7 +201,7 @@ struct RsTypeSerializer
|
|||
static void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
std::map<T,U>& v,
|
||||
const std::string& member_name )
|
||||
const std::string& memberName )
|
||||
{
|
||||
switch(j)
|
||||
{
|
||||
|
@ -225,11 +248,11 @@ struct RsTypeSerializer
|
|||
case RsGenericSerializer::PRINT:
|
||||
{
|
||||
if(v.empty())
|
||||
std::cerr << " Empty map \"" << member_name << "\""
|
||||
std::cerr << " Empty map \"" << memberName << "\""
|
||||
<< std::endl;
|
||||
else
|
||||
std::cerr << " std::map of " << v.size() << " elements: \""
|
||||
<< member_name << "\"" << std::endl;
|
||||
<< memberName << "\"" << std::endl;
|
||||
|
||||
for(typename std::map<T,U>::iterator it(v.begin());it!=v.end();++it)
|
||||
{
|
||||
|
@ -242,6 +265,95 @@ struct RsTypeSerializer
|
|||
}
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
{
|
||||
using namespace rapidjson;
|
||||
|
||||
Document::AllocatorType& allocator = ctx.mJson.GetAllocator();
|
||||
Value arrKey; arrKey.SetString(memberName.c_str(),
|
||||
memberName.length(), allocator);
|
||||
Value arr(kArrayType);
|
||||
|
||||
for (auto& kv : v)
|
||||
{
|
||||
// Use same allocator to avoid deep copy
|
||||
RsGenericSerializer::SerializeContext kCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
serial_process<T>(j, kCtx, const_cast<T&>(kv.first), "key");
|
||||
|
||||
RsGenericSerializer::SerializeContext vCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
serial_process<U>(j, vCtx, const_cast<U&>(kv.second), "value");
|
||||
|
||||
if(kCtx.mOk && vCtx.mOk)
|
||||
{
|
||||
Value el(kObjectType);
|
||||
el.AddMember("key", kCtx.mJson["key"], allocator);
|
||||
el.AddMember("value", vCtx.mJson["value"], allocator);
|
||||
|
||||
arr.PushBack(el, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.mJson.AddMember(arrKey, arr, allocator);
|
||||
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
{
|
||||
using namespace rapidjson;
|
||||
|
||||
bool& ok(ctx.mOk);
|
||||
Document& jDoc(ctx.mJson);
|
||||
Document::AllocatorType& allocator = jDoc.GetAllocator();
|
||||
|
||||
Value arrKey;
|
||||
arrKey.SetString(memberName.c_str(), memberName.length());
|
||||
|
||||
ok = ok && jDoc.IsObject();
|
||||
ok = ok && jDoc.HasMember(arrKey);
|
||||
|
||||
if(ok && jDoc[arrKey].IsArray())
|
||||
{
|
||||
for (auto&& kvEl : jDoc[arrKey].GetArray())
|
||||
{
|
||||
ok = ok && kvEl.IsObject();
|
||||
ok = ok && kvEl.HasMember("key");
|
||||
ok = ok && kvEl.HasMember("value");
|
||||
if (!ok) break;
|
||||
|
||||
RsGenericSerializer::SerializeContext kCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
ok && (kCtx.mJson.
|
||||
AddMember("key", kvEl["key"], allocator), true);
|
||||
|
||||
T key;
|
||||
ok = ok && (serial_process(j, kCtx, key, "key"), kCtx.mOk);
|
||||
|
||||
RsGenericSerializer::SerializeContext vCtx(
|
||||
nullptr, 0, RsGenericSerializer::FORMAT_BINARY,
|
||||
RsGenericSerializer::SERIALIZATION_FLAG_NONE,
|
||||
&allocator );
|
||||
ok && (vCtx.mJson.
|
||||
AddMember("value", kvEl["value"], allocator), true);
|
||||
|
||||
U value;
|
||||
ok = ok && ( serial_process(j, vCtx, value, "value"),
|
||||
vCtx.mOk );
|
||||
|
||||
if(ok) v.insert(std::pair<T,U>(key,value));
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +363,7 @@ struct RsTypeSerializer
|
|||
static void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
std::vector<T>& v,
|
||||
const std::string& member_name )
|
||||
const std::string& memberName )
|
||||
{
|
||||
switch(j)
|
||||
{
|
||||
|
@ -259,7 +371,7 @@ struct RsTypeSerializer
|
|||
{
|
||||
ctx.mOffset += 4;
|
||||
for(uint32_t i=0;i<v.size();++i)
|
||||
serial_process(j,ctx,v[i],member_name);
|
||||
serial_process(j,ctx,v[i],memberName);
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::DESERIALIZE:
|
||||
|
@ -268,7 +380,7 @@ struct RsTypeSerializer
|
|||
serial_process(j,ctx,n,"temporary size");
|
||||
v.resize(n);
|
||||
for(uint32_t i=0;i<v.size();++i)
|
||||
serial_process(j,ctx,v[i],member_name);
|
||||
serial_process(j,ctx,v[i],memberName);
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::SERIALIZE:
|
||||
|
@ -276,7 +388,7 @@ struct RsTypeSerializer
|
|||
uint32_t n=v.size();
|
||||
serial_process(j,ctx,n,"temporary size");
|
||||
for(uint32_t i=0; i<v.size(); ++i)
|
||||
serial_process(j,ctx,v[i],member_name);
|
||||
serial_process(j,ctx,v[i],memberName);
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::PRINT:
|
||||
|
@ -289,10 +401,16 @@ struct RsTypeSerializer
|
|||
for(uint32_t i=0;i<v.size();++i)
|
||||
{
|
||||
std::cerr << " " ;
|
||||
serial_process(j,ctx,v[i],member_name);
|
||||
serial_process(j,ctx,v[i],memberName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
RsTypeSerializer_PRIVATE_TO_JSON_ARRAY();
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(push_back);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -301,7 +419,7 @@ struct RsTypeSerializer
|
|||
template<typename T>
|
||||
static void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
std::set<T>& v, const std::string& member_name )
|
||||
std::set<T>& v, const std::string& memberName )
|
||||
{
|
||||
switch(j)
|
||||
{
|
||||
|
@ -311,7 +429,7 @@ struct RsTypeSerializer
|
|||
for(typename std::set<T>::iterator it(v.begin());it!=v.end();++it)
|
||||
// the const cast here is a hack to avoid serial_process to
|
||||
// instantiate serialise(const T&)
|
||||
serial_process(j,ctx,const_cast<T&>(*it) ,member_name);
|
||||
serial_process(j,ctx,const_cast<T&>(*it) ,memberName);
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::DESERIALIZE:
|
||||
|
@ -321,7 +439,7 @@ struct RsTypeSerializer
|
|||
for(uint32_t i=0; i<n; ++i)
|
||||
{
|
||||
T tmp;
|
||||
serial_process<T>(j,ctx,tmp,member_name);
|
||||
serial_process<T>(j,ctx,tmp,memberName);
|
||||
v.insert(tmp);
|
||||
}
|
||||
break;
|
||||
|
@ -333,7 +451,7 @@ struct RsTypeSerializer
|
|||
for(typename std::set<T>::iterator it(v.begin());it!=v.end();++it)
|
||||
// the const cast here is a hack to avoid serial_process to
|
||||
// instantiate serialise(const T&)
|
||||
serial_process(j,ctx,const_cast<T&>(*it) ,member_name);
|
||||
serial_process(j,ctx,const_cast<T&>(*it) ,memberName);
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::PRINT:
|
||||
|
@ -343,6 +461,12 @@ struct RsTypeSerializer
|
|||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
RsTypeSerializer_PRIVATE_TO_JSON_ARRAY();
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(insert);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -352,7 +476,7 @@ struct RsTypeSerializer
|
|||
static void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
std::list<T>& v,
|
||||
const std::string& member_name )
|
||||
const std::string& memberName )
|
||||
{
|
||||
switch(j)
|
||||
{
|
||||
|
@ -360,7 +484,7 @@ struct RsTypeSerializer
|
|||
{
|
||||
ctx.mOffset += 4;
|
||||
for(typename std::list<T>::iterator it(v.begin());it!=v.end();++it)
|
||||
serial_process(j,ctx,*it ,member_name);
|
||||
serial_process(j,ctx,*it ,memberName);
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::DESERIALIZE:
|
||||
|
@ -370,7 +494,7 @@ struct RsTypeSerializer
|
|||
for(uint32_t i=0;i<n;++i)
|
||||
{
|
||||
T tmp;
|
||||
serial_process<T>(j,ctx,tmp,member_name);
|
||||
serial_process<T>(j,ctx,tmp,memberName);
|
||||
v.push_back(tmp);
|
||||
}
|
||||
break;
|
||||
|
@ -380,7 +504,7 @@ struct RsTypeSerializer
|
|||
uint32_t n=v.size();
|
||||
serial_process(j,ctx,n,"temporary size");
|
||||
for(typename std::list<T>::iterator it(v.begin());it!=v.end();++it)
|
||||
serial_process(j,ctx,*it ,member_name);
|
||||
serial_process(j,ctx,*it ,memberName);
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::PRINT:
|
||||
|
@ -390,6 +514,12 @@ struct RsTypeSerializer
|
|||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
RsTypeSerializer_PRIVATE_TO_JSON_ARRAY();
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
RsTypeSerializer_PRIVATE_FROM_JSON_ARRAY(push_back);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +529,7 @@ struct RsTypeSerializer
|
|||
static void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx,
|
||||
t_RsFlags32<N>& v,
|
||||
const std::string& /*member_name*/)
|
||||
const std::string& memberName )
|
||||
{
|
||||
switch(j)
|
||||
{
|
||||
|
@ -421,16 +551,27 @@ struct RsTypeSerializer
|
|||
std::cerr << " Flags of type " << std::hex << N << " : "
|
||||
<< v.toUInt32() << std::endl;
|
||||
break;
|
||||
case RsGenericSerializer::TO_JSON:
|
||||
ctx.mOk = to_JSON(memberName, v.toUInt32(), ctx.mJson);
|
||||
break;
|
||||
case RsGenericSerializer::FROM_JSON:
|
||||
{
|
||||
uint32_t f;
|
||||
ctx.mOk = from_JSON(memberName, f, ctx.mJson);
|
||||
v = t_RsFlags32<N>(f);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/** TODO
|
||||
* Serialization format is inside context, but context is not passed to
|
||||
* following functions, that need to know the format to do the job, actually
|
||||
* RsGenericSerializer::FORMAT_BINARY is assumed in all of them!!
|
||||
*/
|
||||
|
||||
protected:
|
||||
|
||||
//============================================================================//
|
||||
// Generic types declarations //
|
||||
//============================================================================//
|
||||
|
||||
template<typename T> static bool serialize(
|
||||
uint8_t data[], uint32_t size, uint32_t &offset, const T& member );
|
||||
|
||||
|
@ -442,17 +583,41 @@ protected:
|
|||
template<typename T> static void print_data(
|
||||
const std::string& name, const T& member);
|
||||
|
||||
template<typename T> static bool to_JSON( const std::string& membername,
|
||||
const T& member, RsJson& jDoc );
|
||||
|
||||
template<typename T> static bool from_JSON( const std::string& memberName,
|
||||
T& member, RsJson& jDoc );
|
||||
|
||||
//============================================================================//
|
||||
// Generic types + type_id declarations //
|
||||
//============================================================================//
|
||||
|
||||
template<typename T> static bool serialize(
|
||||
uint8_t data[], uint32_t size, uint32_t &offset, uint16_t type_id,
|
||||
const T& member );
|
||||
|
||||
template<typename T> static bool deserialize(
|
||||
const uint8_t data[], uint32_t size, uint32_t &offset,
|
||||
uint16_t type_id, T& member );
|
||||
|
||||
template<typename T> static uint32_t serial_size(
|
||||
uint16_t type_id,const T& member );
|
||||
template<typename T> static void print_data(
|
||||
const std::string& name,uint16_t type_id,const T& member );
|
||||
|
||||
template<typename T> static void print_data( const std::string& n,
|
||||
uint16_t type_id,const T& member );
|
||||
|
||||
template<typename T> static bool to_JSON( const std::string& membername,
|
||||
uint16_t type_id,
|
||||
const T& member, RsJson& jVal );
|
||||
|
||||
template<typename T> static bool from_JSON( const std::string& memberName,
|
||||
uint16_t type_id,
|
||||
T& member, RsJson& jDoc );
|
||||
|
||||
//============================================================================//
|
||||
// t_RsGenericId<...> declarations //
|
||||
//============================================================================//
|
||||
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
static bool serialize(
|
||||
|
@ -466,13 +631,29 @@ protected:
|
|||
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
static uint32_t serial_size(
|
||||
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member );
|
||||
const t_RsGenericIdType<
|
||||
ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member );
|
||||
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
static void print_data(
|
||||
const std::string& name,
|
||||
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member );
|
||||
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
static bool to_JSON(
|
||||
const std::string& membername,
|
||||
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member,
|
||||
RsJson& jVal );
|
||||
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
static bool from_JSON(
|
||||
const std::string& memberName,
|
||||
t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member,
|
||||
RsJson& jDoc );
|
||||
|
||||
//============================================================================//
|
||||
// t_RsTlvList<...> declarations //
|
||||
//============================================================================//
|
||||
|
||||
template<class TLV_CLASS,uint32_t TLV_TYPE>
|
||||
static bool serialize(
|
||||
|
@ -491,16 +672,33 @@ protected:
|
|||
static void print_data(
|
||||
const std::string& name,
|
||||
const t_RsTlvList<TLV_CLASS,TLV_TYPE>& member);
|
||||
|
||||
template<class TLV_CLASS,uint32_t TLV_TYPE>
|
||||
static bool to_JSON( const std::string& membername,
|
||||
const t_RsTlvList<TLV_CLASS,TLV_TYPE>& member,
|
||||
RsJson& jVal );
|
||||
|
||||
template<class TLV_CLASS,uint32_t TLV_TYPE>
|
||||
static bool from_JSON( const std::string& memberName,
|
||||
t_RsTlvList<TLV_CLASS,TLV_TYPE>& member,
|
||||
RsJson& jDoc );
|
||||
};
|
||||
|
||||
|
||||
//============================================================================//
|
||||
// t_RsGenericId<...> //
|
||||
//============================================================================//
|
||||
|
||||
// t_RsGenericId<>
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
bool RsTypeSerializer::serialize (
|
||||
uint8_t data[], uint32_t size, uint32_t &offset,
|
||||
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member )
|
||||
{ return (*const_cast<const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER> *>(&member)).serialise(data,size,offset); }
|
||||
const t_RsGenericIdType<
|
||||
ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member )
|
||||
{
|
||||
return (*const_cast<const t_RsGenericIdType<
|
||||
ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER> *>(&member)
|
||||
).serialise(data,size,offset);
|
||||
}
|
||||
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
bool RsTypeSerializer::deserialize(
|
||||
|
@ -522,8 +720,45 @@ void RsTypeSerializer::print_data(
|
|||
<< member << std::endl;
|
||||
}
|
||||
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
bool RsTypeSerializer::to_JSON( const std::string& memberName,
|
||||
const t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member,
|
||||
RsJson& jDoc )
|
||||
{
|
||||
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator();
|
||||
|
||||
rapidjson::Value key;
|
||||
key.SetString(memberName.c_str(), memberName.length(), allocator);
|
||||
|
||||
const std::string vStr = member.toStdString();
|
||||
rapidjson::Value value;
|
||||
value.SetString(vStr.c_str(), vStr.length(), allocator);
|
||||
|
||||
jDoc.AddMember(key, value, allocator);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<uint32_t ID_SIZE_IN_BYTES,bool UPPER_CASE,uint32_t UNIQUE_IDENTIFIER>
|
||||
bool RsTypeSerializer::from_JSON( const std::string& membername,
|
||||
t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member,
|
||||
RsJson& jVal )
|
||||
{
|
||||
const char* mName = membername.c_str();
|
||||
bool ret = jVal.HasMember(mName);
|
||||
if(ret)
|
||||
{
|
||||
rapidjson::Value& v = jVal[mName];
|
||||
ret = ret && v.IsString();
|
||||
ret && (member = t_RsGenericIdType<ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>(std::string(v.GetString())), false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//============================================================================//
|
||||
// t_RsTlvList<...> //
|
||||
//============================================================================//
|
||||
|
||||
// t_RsTlvList<>
|
||||
template<class TLV_CLASS,uint32_t TLV_TYPE>
|
||||
bool RsTypeSerializer::serialize(
|
||||
uint8_t data[], uint32_t size, uint32_t &offset,
|
||||
|
@ -553,3 +788,76 @@ void RsTypeSerializer::print_data(
|
|||
std::cerr << " [t_RsTlvString<" << std::hex << TLV_TYPE << ">] : size="
|
||||
<< member.mList.size() << std::endl;
|
||||
}
|
||||
|
||||
template<class TLV_CLASS,uint32_t TLV_TYPE> /* static */
|
||||
bool RsTypeSerializer::to_JSON( const std::string& memberName,
|
||||
const t_RsTlvList<TLV_CLASS,TLV_TYPE>& member,
|
||||
RsJson& jDoc )
|
||||
{
|
||||
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator();
|
||||
|
||||
rapidjson::Value key;
|
||||
key.SetString(memberName.c_str(), memberName.length(), allocator);
|
||||
|
||||
rapidjson::Value value;
|
||||
const char* tName = typeid(member).name();
|
||||
value.SetString(tName, allocator);
|
||||
|
||||
jDoc.AddMember(key, value, allocator);
|
||||
|
||||
std::cerr << __PRETTY_FUNCTION__ << " JSON serialization for type "
|
||||
<< typeid(member).name() << " " << memberName
|
||||
<< " not available." << std::endl;
|
||||
print_stacktrace();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class TLV_CLASS,uint32_t TLV_TYPE>
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
t_RsTlvList<TLV_CLASS,TLV_TYPE>& member,
|
||||
RsJson& /*jVal*/ )
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " JSON deserialization for type "
|
||||
<< typeid(member).name() << " " << memberName
|
||||
<< " not available." << std::endl;
|
||||
print_stacktrace();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================//
|
||||
// Generic types //
|
||||
//============================================================================//
|
||||
|
||||
template<typename T> /*static*/
|
||||
bool RsTypeSerializer::to_JSON(const std::string& memberName, const T& member,
|
||||
RsJson& jDoc )
|
||||
{
|
||||
rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator();
|
||||
|
||||
rapidjson::Value key;
|
||||
key.SetString(memberName.c_str(), memberName.length(), allocator);
|
||||
|
||||
rapidjson::Value value;
|
||||
const char* tName = typeid(member).name();
|
||||
value.SetString(tName, allocator);
|
||||
|
||||
jDoc.AddMember(key, value, allocator);
|
||||
|
||||
std::cerr << __PRETTY_FUNCTION__ << " JSON serialization for type "
|
||||
<< typeid(member).name() << " " << memberName
|
||||
<< " not available." << std::endl;
|
||||
print_stacktrace();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T> /*static*/
|
||||
bool RsTypeSerializer::from_JSON( const std::string& memberName,
|
||||
T& member, RsJson& /*jDoc*/ )
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " JSON deserialization for type "
|
||||
<< typeid(member).name() << " " << memberName
|
||||
<< " not available." << std::endl;
|
||||
print_stacktrace();
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue