macro_rules! py_wrap_data_struct {
    (
        $(#[$meta: meta])*
        $name: ident($rs_inner: ty) $(as $class_name: literal)? {
            $(
            $field_name: ident: $field_rs_type: ty $(=> $convert: ty)+
            ),+
        }
    ) => { ... };
}
Expand description

Wraps a data struct and makes (some of) its fields available to Python.

§Implements

  • Everything implemented by py_wrap_type.
  • PyWrapperMut.
  • get_foo and set_foo methods for field foo, which translate to @property and @foo.setter in Python, i.e. allowing access to the field as a property.

§Warning!

The mutability of exposed fields may not work as you expect.

Since objects are converted back and forth along the FFI boundary using Clones, pointers are not shared like in native Python. In native Python, this code runs without issue:

class Test:
  def __init__(self):
      self.inner = {}

  @property
  def foo(self):
    return self.inner

  @foo.setter
  def foo(self, value):
    self.inner = value

c = Test()
d = c.inner

d["a"] = ["a"]
assert "a" in c.inner

d = c.foo
d["b"] = "b"
assert "b" in c.inner

Using these bindings, assuming that this macro was used to create Test, the equivalent would be:

c = Test()
d = c.foo

d["a"] = ["a"]
assert "a" not in c.foo
c.foo = d
assert "a" in c.foo

§Example

use rigetti_pyo3::pyo3::{Py, types::{PyInt, PyString}};
use rigetti_pyo3::py_wrap_data_struct;

#[derive(Clone)]
pub struct Person {
    pub name: String,
    pub age: u8,
}

py_wrap_data_struct! {
    PyPerson(Person) as "Person" {
        name: String => Py<PyString>,
        age: u8 => Py<PyInt>
    }
}