File serialization.hpp

File List > astutedds > rmw > serialization.hpp

Go to the documentation of this file

//
// Copyright (c) 2026, Astute Systems PTY LTD
//
// This file is part of the AstuteDDS RMW implementation.
//
// See the commercial LICENSE file in the project root for full license details.
//

#pragma once

#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
#include <vector>

#include <astutedds/rmw/type_support.hpp>

// ---------------------------------------------------------------------------
// Writer-side primitives
// ---------------------------------------------------------------------------

inline void
cdr_pad(std::vector<uint8_t> & buf, std::size_t align)
{
    const std::size_t rem = buf.size() % align;
    if (rem)
    {
        buf.insert(buf.end(), align - rem, 0u);
    }
}

template<typename T>
inline void
cdr_write_le(std::vector<uint8_t> & buf, T val)
{
    static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
    const uint8_t * p = reinterpret_cast<const uint8_t *>(&val);
    buf.insert(buf.end(), p, p + sizeof(T));
}

// ---------------------------------------------------------------------------
// Reader-side primitive
// ---------------------------------------------------------------------------

template<typename T>
inline void
cdr_byteswap_inplace(T & v)
{
    static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
    auto * p = reinterpret_cast<uint8_t *>(&v);
    for (std::size_t i = 0, j = sizeof(T) - 1; i < j; ++i, --j)
    {
        const uint8_t tmp = p[i];
        p[i] = p[j];
        p[j] = tmp;
    }
}

struct CdrReader
{
    const uint8_t * buf;  
    std::size_t     len;  
    std::size_t     pos;  
    bool            swap_bytes { false };  

    void align(std::size_t a)
    {
        const std::size_t abs = pos + 4;
        const std::size_t rem = abs % a;
        if (rem) { pos += a - rem; }
    }

    bool read_u8(uint8_t & v)
    {
        if (pos >= len) { return false; }
        v = buf[pos++];
        return true;
    }

    bool read_u16(uint16_t & v)
    {
        align(2);
        if (pos + 2 > len) { return false; }
        std::memcpy(&v, buf + pos, 2);
        if (swap_bytes) { cdr_byteswap_inplace(v); }
        pos += 2;
        return true;
    }

    bool read_u32(uint32_t & v)
    {
        align(4);
        if (pos + 4 > len) { return false; }
        std::memcpy(&v, buf + pos, 4);
        if (swap_bytes) { cdr_byteswap_inplace(v); }
        pos += 4;
        return true;
    }

    bool read_u64(uint64_t & v)
    {
        align(8);
        if (pos + 8 > len) { return false; }
        std::memcpy(&v, buf + pos, 8);
        if (swap_bytes) { cdr_byteswap_inplace(v); }
        pos += 8;
        return true;
    }

    bool read_bytes(void * dst, std::size_t n)
    {
        if (pos + n > len) { return false; }
        std::memcpy(dst, buf + pos, n);
        pos += n;
        return true;
    }
};

// ---------------------------------------------------------------------------
// Mutually-recursive message encode / decode entry points
// (defined in serialization.cpp)
// ---------------------------------------------------------------------------

bool
cdr_encode_c_message(
    const MembersC * members,
    const void *     msg,
    std::vector<uint8_t> & buf);

bool
cdr_decode_c_message(
    const MembersC * members,
    CdrReader &      rdr,
    void *           msg);

bool
cdr_encode_cpp_message(
    const MembersCpp * members,
    const void *       msg,
    std::vector<uint8_t> & buf);

bool
cdr_decode_cpp_message(
    const MembersCpp * members,
    CdrReader &        rdr,
    void *             msg);

// ---------------------------------------------------------------------------
// Public serialize / deserialize wrappers
// ---------------------------------------------------------------------------

bool
serialize_message(
    const TypeSupportHandle & ts,
    const void * ros_message,
    std::vector<uint8_t> & out);

bool
deserialize_message(
    const TypeSupportHandle & ts,
    const uint8_t * data,
    size_t len,
    void * ros_message);