pybind11:用可选数据表示并集

pybind11: Represent union with optional data

我的结构如下所示:

/// 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 中执行此操作的最佳方法。我看过 custom type casters and polymorphic type hooks 的文档,但我不确定哪一个最适合我的用例。

感谢您的帮助!

您有一堆未定义的类型,并且没有指定哪些类型组合有效,因此无法制作 运行 示例,但也许下面的代码可以帮助您。

这个想法是使用 属性 来表示数据,这样你就可以得到一个钩子并在表示方面做任何你想做的事情(我充实了下面的阅读方面,写作会相似)。在钩子中,创建一个占位符对象,检查联合体中哪些成员有效,然后根据需要填充占位符的属性。

#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) {});
}

上面的代码在您的 "only the valid member variables are present" 之后。就个人而言,如果访问当前无效的属性,我会将所有数据成员绑定为属性并简单地引发 ValueError(或 AttributeError 以更接近您的设计)。