#pyo3::PyAny extract into Box<dyn std::any::Any>

7 messages · Page 1 of 1 (latest)

shell socket
#

Is there any way to extract a Python object into a Box<dyn Any>?

I'm not sure if this conceptually makes sense

why?
I can obviously store and move around a Py<PyAny> without extracting in Rust
but when I want to actually use it in Rust I need to extract and for that I need to acquire the GIL
If I could instead extract to a Box<dyn Any> immediately I could downcast later in Rust without acquiring a GIL

I'm open to any dark wizardry or obvious solutions I just didn't notice

long torrent
#

Box<> is allocated by Rust, Py<> is allocated by Python

#

You can't move values between allocators

#

At least not if you don't know exactly what those values contain and how they're structured, which if you're using dyn Any you by definition don't

shell socket
#

yeah I guess that makes sense, thanks

shell socket
#

for anyone maybe trying something similar:

Just guess all the different types when moving from Python to Rust - seems to work for my case and you can probably come up with something prettier (haven't found a match style expression for that yet)

#[derive(Debug)]
pub struct Parameter {
    value: Box<dyn Any + 'static + Send + Sync>,
    clone_fn: fn(&Box<dyn Any + 'static + Send + Sync>) -> Box<dyn Any + 'static + Send + Sync>,
}

impl Parameter {
    pub fn new<T: 'static + Any + Clone + Send + Sync>(t: T) -> Self {
        Parameter {
            value: Box::new(t),
            clone_fn: |x| {
                let x = x.downcast_ref::<T>().unwrap();
                Box::new(x.clone())
            },
        }
    }

    pub fn downcast<T: 'static + Any + Send + Sync>(&self) -> Option<&T> {
        self.value.downcast_ref::<T>()
    }

    pub fn downcast_mut<T: 'static + Any + Send + Sync>(&mut self) -> Option<&mut T> {
        self.value.downcast_mut::<T>()
    }
}

impl<'py> FromPyObject<'py> for Parameter {
    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
        if ob.is_instance_of::<PyFloat>() {
            let value: f64 = ob.extract()?;
            return Ok(Parameter::new(value));
        } else if ob.is_instance_of::<PyString>() {
            let value: String = ob.extract()?;
            return Ok(Parameter::new(value));
        } else if ob.is_instance_of::<PyInt>() {
            let value: i64 = ob.extract()?;
            return Ok(Parameter::new(value));
        } else {
            return Err(pyo3::exceptions::PyTypeError::new_err(
                "Unsupported type for Parameter",
            ));
        }
    }
}
magic zinc
#

that should really just be an enum