pybind11: представить объединение с дополнительными данными

У меня есть структура, которая выглядит следующим образом:

/// Enumeration describing register data types.
typedef enum RegDataType
{
    RegDataType_Unknown       = 0x0,    ///< Unknown register data type.
    RegDataType_ImmMultiData  = 0x1,    ///< Register data type is consecutive register values from a single offset.
    RegDataType_ImmMultiPairs = 0x2,    ///< Register data type is register offset and value pairs.
    RegDataType_IndirectData  = 0x3,    ///< Register data type is consecutive register values from a single offset at
                                        ///  a specified address.
    RegDataType_IndirectPairs = 0x4,    ///< Register data type is register offset and value pairs at a specified 
                                        ///  address.
} RegDataType;


/// Structure representing a register data pair of offset and value.
typedef struct PktRegDataPair
{
    uint32_t offset; ///< The register offset.
    uint32_t value;  ///< The register value.
} PktRegDataPair;

/// Structure representing different types of register data that can be found within a packet.
typedef struct PktRegData
{
    RegDataType type;     ///< Register data type.
    uint32_t    numRegs;  ///< The number of register represented.

    union
    {
        struct
        {
            uint32_t        regOffset;    ///< Starting register offset.
            const uint32_t* pData;        ///< Pointer to consecutive register values.
        } immMultiData;

        struct
        {
            const PktRegDataPair* pData; ///< Pointer to register pairs of offsets/values.
        } immMultiPairs;

        struct
        {
            uint64_t address;    ///< Address of consecutive register values/pairs of offsets/values.
            uint32_t addrOffset; ///< Offset to an existing address. Valid only if address above is zero.
            struct
            {
                uint32_t regOffset;  ///< Starting register offset.
            } data;
        } indirect;
    };
} PktRegData;

Я хотел бы обернуть это в pybind11 таким образом, чтобы при возврате структуры в Python присутствовали только действительные переменные-члены. Точно так же при загрузке из Python мне нужно перевести его в структуру PktRegData.

Я не знаю, как лучше всего это сделать в pybind11. Я видел документацию по кастерам пользовательского типа и хуки полиморфного типа, но я не уверен, что это лучше всего подходит для моего случая использования.

Спасибо за помощь!


person pantaryl    schedule 19.11.2019    source источник


Ответы (1)


У вас есть куча неопределенных типов, и вы не указываете, какие комбинации типов допустимы, поэтому не можете создать работающий пример, но, возможно, приведенный ниже код поможет вам.

Идея состоит в том, чтобы использовать свойство для представления данных, так что вы получаете крючок и делаете там все, что хотите, с точки зрения представления (ниже я конкретизировал сторону чтения, запись будет аналогичной). В хуке создайте объект-заполнитель, проверьте, какие из членов объединения допустимы, затем заполните атрибуты заполнителя соответствующим образом.

#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include "PktRegData.h"

namespace py = pybind11;

struct PyRegData {};         // placeholder

PYBIND11_MODULE(PktRegData, m)
{
    py::class_<PyRegData>(m, "RegData", py::dynamic_attr())
        .def(pybind11::init<>());

    py::class_<PktRegData>(m, "PktRegData")
        .def(pybind11::init<>())
        .def_property("data", [](PktRegData &d) -> pybind11::object {
            auto this_mod = py::module::import("PktRegData");
            py::object data_type = this_mod.attr("RegData");
            py::object data_obj = data_type();

            if (d.type == ...) {
            // just one example of setting properties
                data_obj.attr("regOffset") = py::cast(d.immMultiData.regOffset);
            } else if (d.type == ...) {
                ...
            }

            return data_obj;
        }, [](PktRegData& d) {});
}

Приведенный выше код следует вашему «присутствуют только действительные переменные-члены». Лично я бы привязывал все элементы данных как свойства и просто вызывал бы ValueError (или AttributeError, чтобы оставаться ближе к вашему дизайну), если доступ к атрибуту, который в настоящее время недействителен.

person Wim Lavrijsen    schedule 20.11.2019
comment
Спасибо за помощь! Я отредактировал исходный пост, чтобы определить неопределенное перечисление. По большей части перечисление является достаточно явным, чтобы указать, какие части структуры допустимы. Косвенная структура действительна для обоих значений косвенного перечисления, где indirect.data допустимо только для IndirectData. Это выглядит чрезвычайно полезным, и я попробую это как можно скорее. Спасибо! - person pantaryl; 20.11.2019