Macro rigetti_pyo3::py_wrap_struct
source · macro_rules! py_wrap_struct { ( $(#[$meta: meta])* $name: ident($rs_from: ty) $(as $py_class: literal)? { /// Fallible transformation from Python type `P` to Rust type `T` where `Foo: From<T>`. /// Used to implement `TryFrom<P> for PyFoo`. Any errors returned must be `PyErr`. /// /// $py_for_from should conventionally be `py` -- it is the name of the `Python<'_>` parameter. $($py_for_from: ident -> rs { $($py_ident: ident: $py_src: ty => $rs_dest: ty $to_rs: block),+ },)? /// Fallible transformation from Rust type `T` to Python type `P` where `T: From<Foo>` /// Used to implement `TryFrom<PyFoo> for P`. Any errors returned must be `PyErr`. /// /// $py_for_to should conventionally be `py` -- it is the name of the `Python<'_>` parameter. $(rs -> $py_for_to: ident { $($rs_ident: ident: $rs_src: ty => $py_dest: ty $to_py: block),+ })? } ) => { ... }; }
Expand description
Create a newtype wrapper for a Rust struct.
Implements the following:
- Conversion to/from the contained Rust type
- Conversion to/from the related Python/Rust types
- Constructor taking any type that can be converted from
§Limitations
This macro generates a __new__ constructor for the Python type from the given
py -> rs conversions. This constructor expects exactly one parameter, which cannot
be omitted (i.e. has no default value).
To have more control over the constructor, use py_wrap_type with a manual
implementation in a pymethods impl block.
§Example
use rigetti_pyo3::py_wrap_struct;
use rigetti_pyo3::pyo3::{Py, PyErr, Python};
use rigetti_pyo3::pyo3::conversion::{IntoPy, PyTryFrom, ToPyObject};
use rigetti_pyo3::pyo3::types::{PyDict, PyTuple};
#[derive(Clone)]
pub struct Foo {
bar: String,
baz: f32,
}
impl From<(String, f32)> for Foo {
fn from(tuple: (String, f32)) -> Self {
Self { bar: tuple.0, baz: tuple.1 }
}
}
impl From<Foo> for (String, f32) {
fn from(foo: Foo) -> Self {
(foo.bar, foo.baz)
}
}
py_wrap_struct! {
PyFoo(Foo) {
// Fallible transformation from Python type `P` to Rust type `T` where `Foo: From<T>`.
// Used to implement `TryFrom<P> for PyFoo`. Any errors returned must be `PyErr`.
py -> rs {
py_dict: Py<PyDict> => Foo {
let bar = py_dict.as_ref(py).get_item("bar")?.unwrap().extract().unwrap();
let baz = py_dict.as_ref(py).get_item("baz")?.unwrap().extract().unwrap();
Ok::<_, PyErr>(Foo { bar, baz })
},
py_tuple: Py<PyTuple> => (String, f32) {
Ok::<_, PyErr>((
py_tuple.as_ref(py).get_item(0)?.extract().unwrap(),
py_tuple.as_ref(py).get_item(1)?.extract().unwrap(),
))
}
},
// Infallible transformation from Rust type `T` to Python type `P` where `T: From<Foo>`.
// Used to implement `From<PyFoo> for P`.
rs -> py {
rs_tuple: (String, f32) => Py<PyTuple> {
Python::with_gil(|py| {
let obj = rs_tuple.to_object(py);
<PyTuple as PyTryFrom>::try_from(obj.as_ref(py))
.map(|tuple| tuple.into_py(py))
.map_err(PyErr::from)
})
}
}
}
}