1

I have a struct in Rust that works like a linked-list that I want to expose to Python. The struct has a parent field, which is a reference to a parent which is a struct of the same type. I need to wrap this in a Box, since Rust complains about needing indirection if I don't, but then PyO3 gives the following error:

required for `Box<ListNode>` to implement `pyo3::FromPyObject<'_>`
required for `Box<ListNode>` to implement `PyFunctionArgument<'_, '_>`

A simplified version of the struct looks like below:

#[pyclass]
#[derive(Clone)]
pub struct ListNode {
    pub parent: Option<Box<ListNode>>,
}
#[pymethods]
impl ListNode {
    #[new]
    pub fn new(parent: Option<Box<ListNode>>) -> ListNode {
        ListNode { parent }
    }
}

What do I need to do to implement FromPyObject for Box? Or is there a more correct way to resolve this? It seems like the error occurs whenever there's a Box in Rust, no matter what the contents of the Box are.

EDIT: The full error output from cargo check is below:

error[E0277]: the trait bound `Box<ListNode>: PyClass` is not satisfied
   --> src/ListNode.rs:14:1
    |
14  | #[pymethods]
    | ^^^^^^^^^^^^ the trait `PyClass` is not implemented for `Box<ListNode>`
...
17  |     pub fn new(parent: Option<Box<ListNode>>) -> ListNode {
    |                        ------ required by a bound introduced by this call
    |
    = note: required for `Box<ListNode>` to implement `pyo3::FromPyObject<'_>`
    = note: required for `Box<ListNode>` to implement `PyFunctionArgument<'_, '_>`
note: required by a bound in `extract_optional_argument`
   --> /me/.cargo/registry/src/github.com-1ecc6299db9ec823/pyo3-0.17.3/src/impl_/extract_argument.rs:104:8
    |
104 |     T: PyFunctionArgument<'a, 'py>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `extract_optional_argument`

error[E0277]: the trait bound `Box<ListNode>: PyClass` is not satisfied
  --> src/ListNode.rs:17:24
   |
17 |     pub fn new(parent: Option<Box<ListNode>>) -> ListNode {
   |                        ^^^^^^ the trait `PyClass` is not implemented for `Box<ListNode>`
   |
   = note: required for `Box<ListNode>` to implement `pyo3::FromPyObject<'_>`
   = note: required for `Box<ListNode>` to implement `PyFunctionArgument<'_, '_>`
David Chanin
  • 533
  • 6
  • 17

1 Answers1

0

You can create the Box inside the function:

#[pymethods]
impl ListNode {
    #[new]
    pub fn new(parent: Option<ListNode>) -> ListNode {
        ListNode { parent: parent.map(Box::new) }
    }
}

See also issue #2090.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77