【问题标题】:PyO3 - Deriving FromPyObject for EnumsPyO3 - 为枚举派生 FromPyObject
【发布时间】:2021-07-28 10:57:06
【问题描述】:

我正在尝试使用 PyO3(版本:0.13.2)从 Rust 构建 Python 包。现在我被困在试图让转换为枚举工作。我有一个像这样的简单枚举:

#[derive(FromPyObject)]
#[derive(Copy,Clone,PartialEq,Eq)]
enum Direction {
    Left,
    Right,
    Up,
    Down
}

我按照the documentation 添加了#[derive(FromPyObject)],但是,我收到以下错误:

错误:无法为空结构和变体派生 FromPyObject --> src/main.rs:3:10 | 3 | #[派生(FromPyObject)] |
^^^^^^^^^^^^^ | = 注意:此错误源于派生宏(在 每晚构建,使用 -Z 宏回溯运行以获取更多信息)

在示例中,所有枚举值都有与之关联的类型。如果这是错误的根源,有什么办法可以解决我的枚举吗?

感谢您的帮助。

解决方案

这是我最终得到的解决方案。我是 Rust 新手,所以使用它需要您自担风险。感谢来自this question 的 Ahmed Mehrez 为宏提供了基础。

您需要以下依赖项。

[dependencies]
num-traits = "0.2"
num-derive = "0.3"

宏为枚举实现 IntoPy 和 FromPyObject。它转换为/从 int 转换。另外,您现在可以迭代枚举!

use pyo3::prelude::*;

#[macro_use]
extern crate num_derive;
use num_traits::FromPrimitive;

// https://stackoverflow.com/questions/21371534/in-rust-is-there-a-way-to-iterate-through-the-values-of-an-enum
macro_rules! simple_enum {

    ($visibility:vis, $name:ident, $($member:tt),*) => {

        #[derive(Copy,Clone)]
        $visibility enum $name {$($member),*}

        impl $name {
            fn iterate() -> Vec<$name> {
                vec![$($name::$member,) *]
            }
        }

        impl IntoPy<PyObject> for $name {
            fn into_py(self, py: Python) -> PyObject {
                (self as u8).into_py(py)
            }
        }

        impl FromPyObject<'_> for $name {

            fn extract(ob: &'_ PyAny) -> PyResult<$name> {
        
                let value: u8 = ob.extract().unwrap();

                if let Some(val) = FromPrimitive::from_u8(value) {
                    for member in $name::iterate() {
                        if (member as u8) == val {
                            return Ok(member);
                        }
                    }
                }

                panic!("Invalid value ({}).", value);
            }
        }
    };

    ($name:ident, $($member:tt),*) => {
        simple_enum!(, $name, $($member),*)
    };
}

// Example
simple_enum!(pub, Direction, 
    Left, 
    Right, 
    Up, 
    Down
);

在 Python 中,您需要重新定义枚举并将值与 Rust 模块一起使用。

from enum import Enum
    
class Direction(Enum):
    Left = 1
    Right = 2
    Up = 3
    Down = 4
    
// Direction.Left.value

【问题讨论】:

    标签: rust enums pyo3


    【解决方案1】:

    目前没有此类枚举的派生。 FromPyObject 派生旨在处理来自 Python 端的多态输入,而不是区分单元类型。

    但是,自去年夏天以来,已经有 a stale PR 在 PyO3 上添加一般枚举支持。如果这有一些进展,您将来可能能够处理 Python 枚举。

    在此之前,您需要手动实现 FromPyObject 并决定哪些输入映射到哪个变体。

    如果你想从 Python 传递一个字符串并从中获取 Rust 中匹配的枚举变体,你也可以让你的接口在 Rust 中使用 String,添加一个 impl TryFrom&lt;&amp;str&gt; for Direction 并尝试在你的接口函数中进行转换.

    【讨论】:

      猜你喜欢
      • 2012-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-04
      • 2020-08-16
      • 2015-07-05
      • 1970-01-01
      相关资源
      最近更新 更多