Support IntoPyObject for Arc in pyclass for pyo3(get)
I defined a class
#[pyclass(get_all)]
class MyClass {
inner: Arc<Vec<String>>,
}
and I got the error below
`std::sync::Arc<std::vec::Vec<std::string::String>>` cannot be converted to a Python objec
#4668 is somewhat related, but I think Arc may not have the same issues with semantics in Python that representing a rust atomic integer would?
I think the question here is to define how to convert Arc<T>. We don't have access to a T by value so we can't just forward it that way. I guess it would make the most sense to forward to the implementation for &T using HRTB, but I don't know of a way to name it in the associated types. We could of course erase the types and just return PyAny and PyErr, but I'm not so sure whether we should do that.
impl<'py, T> IntoPyObject<'py> for Arc<T>
where
for<'a> &'a T: IntoPyObject<'py>,
{
type Target = <??>::Target;
type Output = <??>::Output;
type Error = <??>::Error;
#[inline]
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
(&*self).into_pyobject(py)
}
}
It is possible to implement on a reference, which would make it work for #[pyo3(get)] on #[pyclass], but would not work for
#[derive(IntoPyObject)] (only #[derive(IntoPyObjectRef)]) or as return type.
impl<'a, 'py, T> IntoPyObject<'py> for &'a Arc<T>
where
&'a T: IntoPyObject<'py>,
{
type Target = <&'a T as IntoPyObject<'py>>::Target;
type Output = <&'a T as IntoPyObject<'py>>::Output;
type Error = <&'a T as IntoPyObject<'py>>::Error;
#[inline]
fn into_pyobject(self, py: crate::Python<'py>) -> Result<Self::Output, Self::Error> {
(&**self).into_pyobject(py)
}
}
I tend to think that writing a manual #[getter] for these cases is the better option.
but I don't know of a way to name it in the associated types.
You can use additional type parameters. It is not pretty but it works 😅
impl<'py, A, T, O, E> IntoPyObject<'py> for std::sync::Arc<A>
where
for<'a> &'a A: IntoPyObject<'py, Target = T, Output=O, Error = E>,
O: BoundObject<'py, T>,
E: Into<PyErr>
{
type Target = T;
type Output = O;
type Error = E;
#[inline]
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
(&*self).into_pyobject(py)
}
}