#ifndef _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ #define _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ #include "../returnvalues/HasReturnvaluesIF.h" #include "EndianConverter.h" #include "SerializeIF.h" #include #include /** * @brief These adapters provides an interface to use the SerializeIF functions * with arbitrary template objects to facilitate and simplify the * serialization of classes with different multiple different data types * into buffers and vice-versa. * @details * The correct serialization or deserialization function is chosen at * compile time with template type deduction. * * @ingroup serialize */ class SerializeAdapter { public: /*** * This function can be used to serialize a trivial copy-able type or a * child of SerializeIF. * The right template to be called is determined in the function itself. * For objects of non trivial copy-able type this function is almost never * called by the user directly. Instead helpers for specific types like * SerialArrayListAdapter or SerialLinkedListAdapter is the right choice here. * * @param[in] object Object to serialize, the used type is deduced from this pointer * @param[in/out] buffer Buffer to serialize into. Will be moved by the function. * @param[in/out] size Size of current written buffer. Will be incremented by the function. * @param[in] maxSize Max size of Buffer * @param[in] streamEndianness Endianness of serialized element as in according to SerializeIF::Endianness * @return * - @c BUFFER_TOO_SHORT The given buffer in is too short * - @c RETURN_FAILED Generic Error * - @c RETURN_OK Successful serialization */ template static ReturnValue_t serialize(const T *object, uint8_t **buffer, size_t *size, size_t maxSize, SerializeIF::Endianness streamEndianness) { InternalSerializeAdapter::value> adapter; return adapter.serialize(object, buffer, size, maxSize, streamEndianness); } /** * Function to return the serialized size of the object in the pointer. * May be a trivially copy-able object or a Child of SerializeIF * * @param object Pointer to Object * @return Serialized size of object */ template static size_t getSerializedSize(const T *object){ InternalSerializeAdapter::value> adapter; return adapter.getSerializedSize(object); } /** * @brief * Deserializes a object from a given buffer of given size. * Object Must be trivially copy-able or a child of SerializeIF. * * @details * Buffer will be moved to the current read location. Size will be decreased by the function. * * @param[in/out] buffer Buffer to deSerialize from. Will be moved by the function. * @param[in/out] size Remaining size of the buffer to read from. Will be decreased by function. * @param[in] streamEndianness Endianness as in according to SerializeIF::Endianness * @return * - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object * - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected * - @c RETURN_FAILED Generic Error * - @c RETURN_OK Successful deserialization */ template static ReturnValue_t deSerialize(T *object, const uint8_t **buffer, size_t *size, SerializeIF::Endianness streamEndianness) { InternalSerializeAdapter::value> adapter; return adapter.deSerialize(object, buffer, size, streamEndianness); } private: /** * Internal template to deduce the right function calls at compile time */ template class InternalSerializeAdapter; /** * Template to be used if T is not a child of SerializeIF * * @tparam T T must be trivially_copyable */ template class InternalSerializeAdapter { static_assert (std::is_trivially_copyable::value, "If a type needs to be serialized it must be a child of " "SerializeIF or trivially copy-able"); public: static ReturnValue_t serialize(const T *object, uint8_t **buffer, size_t *size, size_t max_size, SerializeIF::Endianness streamEndianness) { size_t ignoredSize = 0; if (size == nullptr) { size = &ignoredSize; } // Check remaining size is large enough and check integer // overflow of *size size_t newSize = sizeof(T) + *size; if ((newSize <= max_size) and (newSize > *size)) { T tmp; switch (streamEndianness) { case SerializeIF::Endianness::BIG: tmp = EndianConverter::convertBigEndian(*object); break; case SerializeIF::Endianness::LITTLE: tmp = EndianConverter::convertLittleEndian(*object); break; default: case SerializeIF::Endianness::MACHINE: tmp = *object; break; } std::memcpy(*buffer, &tmp, sizeof(T)); *size += sizeof(T); (*buffer) += sizeof(T); return HasReturnvaluesIF::RETURN_OK; } else { return SerializeIF::BUFFER_TOO_SHORT; } } ReturnValue_t deSerialize(T *object, const uint8_t **buffer, size_t *size, SerializeIF::Endianness streamEndianness) { T tmp; if (*size >= sizeof(T)) { *size -= sizeof(T); std::memcpy(&tmp, *buffer, sizeof(T)); switch (streamEndianness) { case SerializeIF::Endianness::BIG: *object = EndianConverter::convertBigEndian(tmp); break; case SerializeIF::Endianness::LITTLE: *object = EndianConverter::convertLittleEndian(tmp); break; default: case SerializeIF::Endianness::MACHINE: *object = tmp; break; } *buffer += sizeof(T); return HasReturnvaluesIF::RETURN_OK; } else { return SerializeIF::STREAM_TOO_SHORT; } } uint32_t getSerializedSize(const T *object) { return sizeof(T); } }; /** * Template for objects that inherit from SerializeIF * * @tparam T A child of SerializeIF */ template class InternalSerializeAdapter { public: ReturnValue_t serialize(const T *object, uint8_t **buffer, size_t *size, size_t max_size, SerializeIF::Endianness streamEndianness) const { size_t ignoredSize = 0; if (size == nullptr) { size = &ignoredSize; } return object->serialize(buffer, size, max_size, streamEndianness); } size_t getSerializedSize(const T *object) const { return object->getSerializedSize(); } ReturnValue_t deSerialize(T *object, const uint8_t **buffer, size_t *size, SerializeIF::Endianness streamEndianness) { return object->deSerialize(buffer, size, streamEndianness); } }; }; #endif /* _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ */