LINUX.ORG.RU

Как энкапсулировать объект?

 ,


0

2

Как в pyo3 rust завернуть несовместимый с python объект и вернуть его в пайтон? Мне надо вернуть client_channels не используя pyclass (просто представьте что я его использовал с внешнего моделя). sleep тут здесь для теста GIL.

use pyo3::{prelude::*, wrap_pyfunction};
use tokio;

struct ClientChannels {
    vendor_id: u16,
    product_id: u16,
}

#[pyfunction]
fn sleep(py: Python) -> PyResult<Bound<PyAny>> {
    let client_channels = ClientChannels {
        vendor_id: 1,
        product_id: 2,
    };

    pyo3_async_runtimes::tokio::future_into_py(py, async move {
        tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
        Ok(client_channels)
    })
}

#[pymodule]
fn libhidproxy(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(sleep, m)?)?;
    Ok(())
}

Всё оказалось проще, достаточно указатель в виде целого вернуть.

use pyo3::{prelude::*, wrap_pyfunction};
use std::boxed::Box;

#[pyfunction]
fn create_client_channels() -> usize {
    let client_channels = ClientChannels {
        vendor_id: 1,
        product_id: 2,
    };

    let boxed = Box::new(client_channels);
    Box::into_raw(boxed) as usize
}

#[pyfunction]
fn get_vendor_id(ptr: usize) -> PyResult<u16> {
    let channels = unsafe { &*(ptr as *const ClientChannels) };
    Ok(channels.vendor_id)
}

#[pyfunction]
fn get_product_id(ptr: usize) -> PyResult<u16> {
    let channels = unsafe { &*(ptr as *const ClientChannels) };
    Ok(channels.product_id)
}

#[pyfunction]
fn free_client_channels(ptr: usize) -> PyResult<()> {
    unsafe {
        drop(Box::from_raw(ptr as *mut ClientChannels));
    }
    Ok(())
}

#[pymodule]
fn libhidproxy(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(create_client_channels, m)?)?;
    m.add_function(wrap_pyfunction!(get_vendor_id, m)?)?;
    m.add_function(wrap_pyfunction!(get_product_id, m)?)?;
    m.add_function(wrap_pyfunction!(free_client_channels, m)?)?;
    Ok(())
}
★★★★★

Последнее исправление: steemandlinux (всего исправлений: 2)

несовместимый с python объект и вернуть его в пайтон

Никак. В питоне всё объект, причём валидный pyobject. Но не обязательно конечно для всего на свете использовать свои хитрые классы, можно и кортеж из двух чисел вернуть.

neumond
()
Ответ на: комментарий от neumond

dataclass (namedtuple) али ещё какой «pod» с pydantic-like декорацией для фан-шуе

ps:


import struct #фроде как раз для интеропа каменного века 
qulinxao3 ★☆
()
Последнее исправление: qulinxao3 (всего исправлений: 1)

дык «сереализуй» если на стороне питона особо не будешь вглядываться то будет транзитится из/в rust

т.е для питона это будет имутабильная «строка» а по факту посссылка-rustоманская - клёвая архе туктура

qulinxao3 ★☆
()
Ответ на: комментарий от mittorn

Нет, оно не течёт, оно вручную через drop box удаляется. Владелец пайтон, поэтому указатель всегда доступен по адресу.

Поэтому когда в питухончике пишешь, надо убедиться, что у тебя всегда одиночный free на инициализированном объекте, т.е. не лениться занулять указатель в переменной. А то в нём как нефиг сделать double free по привычке.

steemandlinux ★★★★★
() автор топика
Последнее исправление: steemandlinux (всего исправлений: 1)