From 1313867211ca522f6e3ace823c1148bf67e97523 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Tue, 10 Sep 2024 14:49:17 +0200 Subject: [PATCH 01/11] Migrate to pyo3 v0.21 --- Cargo.lock | 20 ++--- Cargo.toml | 2 +- runtime/Cargo.toml | 2 +- runtime/src/lib.rs | 208 +++++++++++++++++++++++++-------------------- src/python.rs | 22 +++-- 5 files changed, 142 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d2d40b3..dd7b198 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1459,9 +1459,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233" +checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" dependencies = [ "cfg-if", "indoc", @@ -1478,9 +1478,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" +checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" dependencies = [ "once_cell", "target-lexicon", @@ -1488,9 +1488,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa" +checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" dependencies = [ "libc", "pyo3-build-config", @@ -1498,9 +1498,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158" +checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -1510,9 +1510,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.20.3" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185" +checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" dependencies = [ "heck 0.4.1", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 0d27fc5..4ba511b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ wasmparser = "0.216.0" indexmap = "2.5.0" bincode = "1.3.3" heck = "0.5.0" -pyo3 = { version = "0.20.0", features = [ +pyo3 = { version = "0.21.2", features = [ "abi3-py37", "extension-module", ], optional = true } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 91edd8f..80a58c2 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["staticlib"] [dependencies] anyhow = "1.0.86" once_cell = "1.19.0" -pyo3 = { version = "0.20.0", features = ["abi3-py311", "num-bigint"] } +pyo3 = { version = "0.21.2", features = ["abi3-py311", "num-bigint"] } componentize-py-shared = { path = "../shared" } num-bigint = "0.4.6" wit-bindgen = "0.16.0" diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index fb32a5b..bdaf5d4 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -12,8 +12,11 @@ use { pyo3::{ exceptions::PyAssertionError, intern, - types::{PyBool, PyBytes, PyDict, PyList, PyMapping, PyModule, PyString, PyTuple}, - Py, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, + types::{ + PyAnyMethods, PyBool, PyBytes, PyDict, PyList, PyListMethods, PyMapping, + PyMappingMethods, PyModule, PyString, PyTuple, + }, + Borrowed, Bound, Py, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }, std::{ alloc::{self, Layout}, @@ -127,7 +130,7 @@ extern "C" { #[pyo3::pyfunction] #[pyo3(pass_module)] fn call_import<'a>( - module: &'a PyModule, + module: &'a Bound, index: u32, params: Vec<&PyAny>, result_count: usize, @@ -150,7 +153,7 @@ fn call_import<'a>( #[pyo3::pyfunction] #[pyo3(pass_module)] -fn drop_resource(module: &PyModule, index: u32, handle: usize) -> PyResult<()> { +fn drop_resource(module: &Bound, index: u32, handle: usize) -> PyResult<()> { let params = [handle]; unsafe { componentize_py_call_indirect( @@ -165,7 +168,7 @@ fn drop_resource(module: &PyModule, index: u32, handle: usize) -> PyResult<()> { #[pyo3::pymodule] #[pyo3(name = "componentize_py_runtime")] -fn componentize_py_module(_py: Python<'_>, module: &PyModule) -> PyResult<()> { +fn componentize_py_module(_py: Python<'_>, module: &Bound) -> PyResult<()> { module.add_function(pyo3::wrap_pyfunction!(call_import, module)?)?; module.add_function(pyo3::wrap_pyfunction!(drop_resource, module)?) } @@ -176,7 +179,7 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { - let app = match py.import(app_name.as_str()) { + let app = match py.import_bound(app_name.as_str()) { Ok(app) => app, Err(e) => { e.print(py); @@ -198,37 +201,37 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { protocol, name, }) => Export::Freestanding { - name: PyString::intern(py, name).into(), + name: PyString::intern_bound(py, name).into(), instance: py - .import(module.as_str())? + .import_bound(module.as_str())? .getattr(protocol.as_str())? .call0()? .into(), }, FunctionExport::Freestanding(Function { protocol, name }) => { Export::Freestanding { - name: PyString::intern(py, name).into(), + name: PyString::intern_bound(py, name).into(), instance: app.getattr(protocol.as_str())?.call0()?.into(), } } FunctionExport::Constructor(Constructor { module, protocol }) => { Export::Constructor( - py.import(module.as_str())? + py.import_bound(module.as_str())? .getattr(protocol.as_str())? .into(), ) } FunctionExport::Method(name) => { - Export::Method(PyString::intern(py, name).into()) + Export::Method(PyString::intern_bound(py, name).into()) } FunctionExport::Static(Static { module, protocol, name, }) => Export::Static { - name: PyString::intern(py, name).into(), + name: PyString::intern_bound(py, name).into(), class: py - .import(module.as_str())? + .import_bound(module.as_str())? .getattr(protocol.as_str())? .into(), }, @@ -252,13 +255,13 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { }) => match kind { OwnedKind::Record(fields) => Type::Record { constructor: py - .import(package.as_str())? + .import_bound(package.as_str())? .getattr(name.as_str())? .into(), fields, }, OwnedKind::Variant(cases) => { - let package = py.import(package.as_str())?; + let package = py.import_bound(package.as_str())?; let cases = cases .iter() @@ -272,7 +275,7 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { }) .collect::>>()?; - let types_to_discriminants = PyDict::new(py); + let types_to_discriminants = PyDict::new_bound(py); for (index, case) in cases.iter().enumerate() { types_to_discriminants .set_item(&case.constructor, index)?; @@ -285,21 +288,21 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { } OwnedKind::Enum(count) => Type::Enum { constructor: py - .import(package.as_str())? + .import_bound(package.as_str())? .getattr(name.as_str())? .into(), count: count.try_into().unwrap(), }, OwnedKind::Flags(u32_count) => Type::Flags { constructor: py - .import(package.as_str())? + .import_bound(package.as_str())? .getattr(name.as_str())? .into(), u32_count: u32_count.try_into().unwrap(), }, OwnedKind::Resource(Resource { local, remote }) => Type::Resource { constructor: py - .import(package.as_str())? + .import_bound(package.as_str())? .getattr(name.as_str())? .into(), local, @@ -317,16 +320,16 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { ) .unwrap(); - let types = py.import(symbols.types_package.as_str())?; + let types = py.import_bound(symbols.types_package.as_str())?; SOME_CONSTRUCTOR.set(types.getattr("Some")?.into()).unwrap(); OK_CONSTRUCTOR.set(types.getattr("Ok")?.into()).unwrap(); ERR_CONSTRUCTOR.set(types.getattr("Err")?.into()).unwrap(); let environ = py - .import("os")? + .import_bound("os")? .getattr("environ")? - .downcast::() + .extract::>() .unwrap(); let keys = environ.keys()?; @@ -338,24 +341,24 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { ENVIRON.set(environ.into()).unwrap(); FINALIZE - .set(py.import("weakref")?.getattr("finalize")?.into()) + .set(py.import_bound("weakref")?.getattr("finalize")?.into()) .unwrap(); DROP_RESOURCE .set( - py.import("componentize_py_runtime")? + py.import_bound("componentize_py_runtime")? .getattr("drop_resource")? .into(), ) .unwrap(); - SEED.set(py.import("random")?.getattr("seed")?.into()) + SEED.set(py.import_bound("random")?.getattr("seed")?.into()) .unwrap(); let argv = py - .import("sys")? + .import_bound("sys")? .getattr("argv")? - .downcast::() + .extract::>() .unwrap(); for i in 0..argv.len() { @@ -429,14 +432,14 @@ pub unsafe extern "C" fn componentize_py_dispatch( ONCE.call_once(|| { // We must call directly into the host to get the runtime environment since libc's version will only // contain the build-time pre-init snapshot. - let environ = ENVIRON.get().unwrap().as_ref(py); + let environ = ENVIRON.get().unwrap().bind(py); for (k, v) in environment::get_environment() { environ.set_item(k, v).unwrap(); } // Likewise for CLI arguments. for arg in environment::get_arguments() { - ARGV.get().unwrap().as_ref(py).append(arg).unwrap(); + ARGV.get().unwrap().bind(py).append(arg).unwrap(); } // Call `random.seed()` to ensure we get a fresh seed rather than the one that got baked in during @@ -448,15 +451,15 @@ pub unsafe extern "C" fn componentize_py_dispatch( let export = &EXPORTS.get().unwrap()[export]; let result = match export { Export::Freestanding { instance, name } => { - instance.call_method1(py, name.as_ref(py), PyTuple::new(py, params_py)) + instance.call_method1(py, name.bind(py), PyTuple::new_bound(py, params_py)) } - Export::Constructor(class) => class.call1(py, PyTuple::new(py, params_py)), + Export::Constructor(class) => class.call1(py, PyTuple::new_bound(py, params_py)), Export::Method(name) => params_py[0] - .call_method1(name.as_ref(py), PyTuple::new(py, ¶ms_py[1..])) + .call_method1(name.bind(py), PyTuple::new_bound(py, ¶ms_py[1..])) .map(|r| r.into()), Export::Static { class, name } => class - .getattr(py, name.as_ref(py)) - .and_then(|function| function.call1(py, PyTuple::new(py, params_py))), + .getattr(py, name.bind(py)) + .and_then(|function| function.call1(py, PyTuple::new_bound(py, params_py))), }; let result = match return_style { @@ -473,8 +476,8 @@ pub unsafe extern "C" fn componentize_py_dispatch( if ERR_CONSTRUCTOR .get() .unwrap() - .as_ref(py) - .eq(result.get_type(py)) + .bind(py) + .eq(result.get_type_bound(py)) .unwrap() { result.to_object(py) @@ -486,7 +489,7 @@ pub unsafe extern "C" fn componentize_py_dispatch( }, }; - let result = result.into_ref(py); + let result = result.into_bound(py); let result_array = [result]; componentize_py_call_indirect( @@ -514,7 +517,7 @@ pub unsafe extern "C" fn componentize_py_free(ptr: *mut u8, size: usize, align: #[export_name = "componentize-py#ToCanonBool"] pub extern "C" fn componentize_py_to_canon_bool(_py: &Python, value: &PyAny) -> u32 { - if value.is_true().unwrap() { + if value.is_truthy().unwrap() { 1 } else { 0 @@ -567,10 +570,10 @@ pub unsafe extern "C" fn componentize_py_to_canon_string( #[export_name = "componentize-py#GetField"] pub extern "C" fn componentize_py_get_field<'a>( py: &'a Python, - value: &'a PyAny, + value: Bound<'a, PyAny>, ty: usize, field: usize, -) -> &'a PyAny { +) -> Bound<'a, PyAny> { match &TYPES.get().unwrap()[ty] { Type::Record { fields, .. } => value.getattr(fields[field].as_str()).unwrap(), Type::Variant { @@ -578,9 +581,8 @@ pub extern "C" fn componentize_py_get_field<'a>( cases, } => { let discriminant = types_to_discriminants - .as_ref(*py) + .bind(*py) .get_item(value.get_type()) - .unwrap() .unwrap(); match i32::try_from(field).unwrap() { @@ -589,7 +591,7 @@ pub extern "C" fn componentize_py_get_field<'a>( if cases[discriminant.extract::().unwrap()].has_payload { value.getattr("value").unwrap() } else { - py.None().into_ref(*py) + py.None().into_bound(*py) } } _ => unreachable!(), @@ -597,7 +599,7 @@ pub extern "C" fn componentize_py_get_field<'a>( } Type::Enum { .. } => match i32::try_from(field).unwrap() { DISCRIMINANT_FIELD_INDEX => value.getattr("value").unwrap(), - PAYLOAD_FIELD_INDEX => py.None().into_ref(*py), + PAYLOAD_FIELD_INDEX => py.None().into_bound(*py), _ => unreachable!(), }, Type::Flags { u32_count, .. } => { @@ -613,15 +615,15 @@ pub extern "C" fn componentize_py_get_field<'a>( unsafe { mem::transmute::(value) } .to_object(*py) - .into_ref(*py) - .downcast() + .into_bound(*py) + .extract() .unwrap() } Type::Option => match i32::try_from(field).unwrap() { DISCRIMINANT_FIELD_INDEX => if value.is_none() { 0 } else { 1 } .to_object(*py) - .into_ref(*py) - .downcast() + .into_bound(*py) + .extract() .unwrap(), PAYLOAD_FIELD_INDEX => value, _ => unreachable!(), @@ -629,8 +631,8 @@ pub extern "C" fn componentize_py_get_field<'a>( Type::NestingOption => match i32::try_from(field).unwrap() { DISCRIMINANT_FIELD_INDEX => if value.is_none() { 0 } else { 1 } .to_object(*py) - .into_ref(*py) - .downcast() + .into_bound(*py) + .extract() .unwrap(), PAYLOAD_FIELD_INDEX => { if value.is_none() { @@ -645,7 +647,7 @@ pub extern "C" fn componentize_py_get_field<'a>( DISCRIMINANT_FIELD_INDEX => if OK_CONSTRUCTOR .get() .unwrap() - .as_ref(*py) + .bind(*py) .eq(value.get_type()) .unwrap() { @@ -653,7 +655,7 @@ pub extern "C" fn componentize_py_get_field<'a>( } else if ERR_CONSTRUCTOR .get() .unwrap() - .as_ref(*py) + .bind(*py) .eq(value.get_type()) .unwrap() { @@ -662,7 +664,7 @@ pub extern "C" fn componentize_py_get_field<'a>( unreachable!() } .to_object(*py) - .into_ref(*py), + .into_bound(*py), PAYLOAD_FIELD_INDEX => value.getattr("value").unwrap(), _ => unreachable!(), }, @@ -697,38 +699,56 @@ pub extern "C" fn componentize_py_get_list_element<'a>( } #[export_name = "componentize-py#FromCanonBool"] -pub extern "C" fn componentize_py_from_canon_bool<'a>(py: &'a Python<'a>, value: u32) -> &'a PyAny { - PyBool::new(*py, value != 0) +pub extern "C" fn componentize_py_from_canon_bool<'a, 'py>( + py: &'a Python<'py>, + value: u32, +) -> Borrowed<'a, 'py, PyBool> { + PyBool::new_bound(*py, value != 0) } #[export_name = "componentize-py#FromCanonI32"] -pub extern "C" fn componentize_py_from_canon_i32<'a>(py: &'a Python<'a>, value: i32) -> &'a PyAny { - value.to_object(*py).into_ref(*py).downcast().unwrap() +pub extern "C" fn componentize_py_from_canon_i32<'a>( + py: &'a Python<'a>, + value: i32, +) -> Bound<'a, PyAny> { + value.to_object(*py).into_bound(*py).extract().unwrap() } #[export_name = "componentize-py#FromCanonI64"] -pub extern "C" fn componentize_py_from_canon_i64<'a>(py: &'a Python<'a>, value: i64) -> &'a PyAny { - value.to_object(*py).into_ref(*py).downcast().unwrap() +pub extern "C" fn componentize_py_from_canon_i64<'a>( + py: &'a Python<'a>, + value: i64, +) -> Bound<'a, PyAny> { + value.to_object(*py).into_bound(*py).extract().unwrap() } #[export_name = "componentize-py#FromCanonF32"] -pub extern "C" fn componentize_py_from_canon_f32<'a>(py: &'a Python<'a>, value: f32) -> &'a PyAny { - value.to_object(*py).into_ref(*py).downcast().unwrap() +pub extern "C" fn componentize_py_from_canon_f32<'a>( + py: &'a Python<'a>, + value: f32, +) -> Bound<'a, PyAny> { + value.to_object(*py).into_bound(*py).extract().unwrap() } #[export_name = "componentize-py#FromCanonF64"] -pub extern "C" fn componentize_py_from_canon_f64<'a>(py: &'a Python<'a>, value: f64) -> &'a PyAny { - value.to_object(*py).into_ref(*py).downcast().unwrap() +pub extern "C" fn componentize_py_from_canon_f64<'a>( + py: &'a Python<'a>, + value: f64, +) -> Bound<'a, PyAny> { + value.to_object(*py).into_bound(*py).extract().unwrap() } #[export_name = "componentize-py#FromCanonChar"] -pub extern "C" fn componentize_py_from_canon_char<'a>(py: &'a Python<'a>, value: u32) -> &'a PyAny { +pub extern "C" fn componentize_py_from_canon_char<'a>( + py: &'a Python<'a>, + value: u32, +) -> Bound<'a, PyAny> { char::from_u32(value) .unwrap() .to_string() .to_object(*py) - .into_ref(*py) - .downcast() + .into_bound(*py) + .extract() .unwrap() } @@ -739,11 +759,10 @@ pub unsafe extern "C" fn componentize_py_from_canon_string<'a>( py: &'a Python, data: *const u8, len: usize, -) -> &'a PyAny { - PyString::new(*py, unsafe { +) -> Bound<'a, PyString> { + PyString::new_bound(*py, unsafe { str::from_utf8_unchecked(slice::from_raw_parts(data, len)) }) - .as_ref() } /// # Safety @@ -752,14 +771,17 @@ pub unsafe extern "C" fn componentize_py_from_canon_string<'a>( pub unsafe extern "C" fn componentize_py_init<'a>( py: &'a Python<'a>, ty: usize, - data: *const &'a PyAny, + data: *const Bound<'a, PyAny>, len: usize, -) -> &'a PyAny { +) -> Bound<'a, PyAny> { match &TYPES.get().unwrap()[ty] { Type::Record { constructor, .. } => constructor - .call1(*py, PyTuple::new(*py, slice::from_raw_parts(data, len))) + .call1( + *py, + PyTuple::new_bound(*py, slice::from_raw_parts(data, len)), + ) .unwrap() - .into_ref(*py), + .into_bound(*py), Type::Variant { cases, .. } => { assert!(len == 2); let discriminant = @@ -778,7 +800,7 @@ pub unsafe extern "C" fn componentize_py_init<'a>( case.constructor.call1(*py, ()) } .unwrap() - .into_ref(*py) + .into_bound(*py) } Type::Enum { constructor, count } => { assert!(len == 2); @@ -795,7 +817,7 @@ pub unsafe extern "C" fn componentize_py_init<'a>( )),), ) .unwrap() - .into_ref(*py) + .into_bound(*py) } Type::Flags { constructor, @@ -808,12 +830,12 @@ pub unsafe extern "C" fn componentize_py_init<'a>( (BigUint::new( slice::from_raw_parts(data, len) .iter() - .map(|&v| mem::transmute::(v.extract().unwrap())) + .map(|v| mem::transmute::(v.extract().unwrap())) .collect(), ),), ) .unwrap() - .into_ref(*py) + .into_bound(*py) } Type::Option => { assert!(len == 2); @@ -823,7 +845,7 @@ pub unsafe extern "C" fn componentize_py_init<'a>( .unwrap(); match discriminant { - 0 => py.None().into_ref(*py), + 0 => py.None().into_bound(*py), 1 => ptr::read(data.offset(isize::try_from(PAYLOAD_FIELD_INDEX).unwrap())), _ => unreachable!(), @@ -837,7 +859,7 @@ pub unsafe extern "C" fn componentize_py_init<'a>( .unwrap(); match discriminant { - 0 => py.None().into_ref(*py), + 0 => py.None().into_bound(*py), 1 => SOME_CONSTRUCTOR .get() @@ -849,7 +871,7 @@ pub unsafe extern "C" fn componentize_py_init<'a>( ),), ) .unwrap() - .into_ref(*py), + .into_bound(*py), _ => unreachable!(), } @@ -873,19 +895,19 @@ pub unsafe extern "C" fn componentize_py_init<'a>( ),), ) .unwrap() - .into_ref(*py) + .into_bound(*py) } Type::Tuple(length) => { assert!(*length == len); - PyTuple::new(*py, slice::from_raw_parts(data, len)) + PyTuple::new_bound(*py, slice::from_raw_parts(data, len)).into_any() } Type::Handle | Type::Resource { .. } => unreachable!(), } } #[export_name = "componentize-py#MakeList"] -pub extern "C" fn componentize_py_make_list<'a>(py: &'a Python) -> &'a PyList { - PyList::empty(*py) +pub extern "C" fn componentize_py_make_list<'a>(py: &'a Python) -> Bound<'a, PyList> { + PyList::empty_bound(*py) } #[export_name = "componentize-py#ListAppend"] @@ -894,8 +916,8 @@ pub extern "C" fn componentize_py_list_append(_py: &Python, list: &PyList, eleme } #[export_name = "componentize-py#None"] -pub extern "C" fn componentize_py_none<'a>(py: &'a Python) -> &'a PyAny { - py.None().into_ref(*py) +pub extern "C" fn componentize_py_none<'a>(py: &'a Python) -> Bound<'a, PyAny> { + py.None().into_bound(*py) } /// # Safety @@ -918,8 +940,8 @@ pub unsafe extern "C" fn componentize_py_make_bytes<'a>( py: &'a Python, src: *const u8, len: usize, -) -> &'a PyAny { - PyBytes::new_with(*py, len, |dst| { +) -> Bound<'a, PyBytes> { + PyBytes::new_bound_with(*py, len, |dst| { dst.copy_from_slice(slice::from_raw_parts(src, len)); Ok(()) }) @@ -933,7 +955,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( borrow: i32, local: i32, resource: i32, -) -> &'a PyAny { +) -> Bound { let ty = &TYPES.get().unwrap()[usize::try_from(resource).unwrap()]; let Type::Resource { constructor, @@ -946,7 +968,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( if local != 0 { if borrow != 0 { - unsafe { PyObject::from_borrowed_ptr(*py, value as usize as _) }.into_ref(*py) + unsafe { PyObject::from_borrowed_ptr(*py, value as usize as _) }.into_bound(*py) } else { let Some(LocalResource { rep, .. }) = resource_local else { panic!("expected local resource, found {ty:?}"); @@ -966,7 +988,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( } }; - let value = unsafe { PyObject::from_borrowed_ptr(*py, rep as _) }.into_ref(*py); + let value = unsafe { PyObject::from_borrowed_ptr(*py, rep as _) }.into_bound(*py); value .delattr(intern!(*py, "__componentize_py_handle")) @@ -989,7 +1011,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( .call_method1( *py, intern!(*py, "__new__"), - PyTuple::new(*py, [constructor]), + PyTuple::new_bound(*py, [constructor]), ) .unwrap(); @@ -1017,7 +1039,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( .setattr(*py, intern!(*py, "finalizer"), finalizer) .unwrap(); - instance.into_ref(*py) + instance.into_bound(*py) } } diff --git a/src/python.rs b/src/python.rs index 00d24c6..b8b7a38 100644 --- a/src/python.rs +++ b/src/python.rs @@ -1,5 +1,10 @@ use { - pyo3::{exceptions::PyAssertionError, types::PyModule, PyResult, Python}, + pyo3::{ + exceptions::PyAssertionError, + pybacked::PyBackedStr, + types::{PyAnyMethods, PyModule}, + Bound, PyResult, Python, + }, std::{ffi::OsString, path::PathBuf}, tokio::runtime::Runtime, }; @@ -11,8 +16,8 @@ use { fn python_componentize( wit_path: Option, world: Option<&str>, - python_path: Vec<&str>, - module_worlds: Vec<(&str, &str)>, + python_path: Vec, + module_worlds: Vec<(PyBackedStr, PyBackedStr)>, app_name: &str, output_path: PathBuf, stub_wasi: bool, @@ -21,8 +26,11 @@ fn python_componentize( Runtime::new()?.block_on(crate::componentize( wit_path.as_deref(), world, - &python_path, - &module_worlds, + &python_path.iter().map(|s| &**s).collect::>(), + &module_worlds + .iter() + .map(|(a, b)| (&**a, &**b)) + .collect::>(), app_name, &output_path, None, @@ -49,7 +57,7 @@ fn python_generate_bindings( #[pyo3(name = "script")] fn python_script(py: Python) -> PyResult<()> { crate::command::run( - py.import("sys")? + py.import_bound("sys")? .getattr("argv")? .extract::>()?, ) @@ -57,7 +65,7 @@ fn python_script(py: Python) -> PyResult<()> { } #[pyo3::pymodule] -fn componentize_py(_py: Python, module: &PyModule) -> PyResult<()> { +fn componentize_py(_py: Python, module: &Bound) -> PyResult<()> { module.add_function(pyo3::wrap_pyfunction!(python_componentize, module)?)?; module.add_function(pyo3::wrap_pyfunction!(python_generate_bindings, module)?)?; module.add_function(pyo3::wrap_pyfunction!(python_script, module)?)?; From 6f26d4f11d0c75002e82faa79fa74bb0a6a88d37 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Tue, 10 Sep 2024 15:14:43 +0200 Subject: [PATCH 02/11] Update to pyo3 v0.22 --- Cargo.lock | 75 ++++++++++----------------------------- Cargo.toml | 6 ++-- runtime/Cargo.toml | 8 +++-- runtime/src/lib.rs | 40 +++++++++++---------- src/python.rs | 2 +- test-generator/Cargo.toml | 2 +- 6 files changed, 51 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd7b198..a984351 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" dependencies = [ "backtrace", ] @@ -1206,16 +1206,6 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.22" @@ -1329,29 +1319,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - [[package]] name = "paste" version = "1.0.15" @@ -1459,16 +1426,16 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" +checksum = "831e8e819a138c36e212f3af3fd9eeffed6bf1510a805af35b0edee5ffa59433" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", "num-bigint", - "parking_lot", + "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", @@ -1478,9 +1445,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" +checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8" dependencies = [ "once_cell", "target-lexicon", @@ -1488,9 +1455,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" +checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6" dependencies = [ "libc", "pyo3-build-config", @@ -1498,9 +1465,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" +checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -1510,11 +1477,11 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.21.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" +checksum = "ec480c0c51ddec81019531705acac51bcdbeae563557c982aa8263bb96880372" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "pyo3-build-config", "quote", @@ -1711,12 +1678,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "semver" version = "1.0.23" @@ -1728,18 +1689,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 4ba511b..7567e40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ name = "componentize_py" crate-type = ["cdylib", "rlib"] [dependencies] -anyhow = { version = "1.0.86", features = ["backtrace"] } +anyhow = { version = "1.0.87", features = ["backtrace"] } clap = { version = "4.5.17", features = ["derive"] } tar = "0.4.41" tempfile = "3.12.0" @@ -22,7 +22,7 @@ wasmparser = "0.216.0" indexmap = "2.5.0" bincode = "1.3.3" heck = "0.5.0" -pyo3 = { version = "0.21.2", features = [ +pyo3 = { version = "0.22.2", features = [ "abi3-py37", "extension-module", ], optional = true } @@ -44,7 +44,7 @@ bytes = "1.7.1" pretty_env_logger = "0.5.0" cap-std = "3.2.0" im-rc = "15.1.0" -serde = { version = "1.0.209", features = ["derive"] } +serde = { version = "1.0.210", features = ["derive"] } toml = "0.8.19" semver = "1.0.23" diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 80a58c2..ba59622 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -7,9 +7,13 @@ edition = "2021" crate-type = ["staticlib"] [dependencies] -anyhow = "1.0.86" +anyhow = "1.0.87" once_cell = "1.19.0" -pyo3 = { version = "0.21.2", features = ["abi3-py311", "num-bigint"] } +pyo3 = { version = "0.22.2", features = [ + "abi3-py311", + "num-bigint", + "py-clone", +] } componentize-py-shared = { path = "../shared" } num-bigint = "0.4.6" wit-bindgen = "0.16.0" diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index bdaf5d4..9c5e3d6 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -13,8 +13,8 @@ use { exceptions::PyAssertionError, intern, types::{ - PyAnyMethods, PyBool, PyBytes, PyDict, PyList, PyListMethods, PyMapping, - PyMappingMethods, PyModule, PyString, PyTuple, + PyAnyMethods, PyBool, PyBytes, PyBytesMethods, PyDict, PyList, PyListMethods, + PyMapping, PyMappingMethods, PyModule, PyModuleMethods, PyString, PyTuple, }, Borrowed, Bound, Py, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }, @@ -132,7 +132,7 @@ extern "C" { fn call_import<'a>( module: &'a Bound, index: u32, - params: Vec<&PyAny>, + params: Vec>, result_count: usize, ) -> PyResult> { let mut results = vec![MaybeUninit::<&PyAny>::uninit(); result_count]; @@ -425,7 +425,7 @@ pub unsafe extern "C" fn componentize_py_dispatch( ); // todo: is this sound, or do we need to `.into_iter().map(MaybeUninit::assume_init).collect()` instead? - let params_py = mem::transmute::>, Vec<&PyAny>>(params_py); + let params_py = mem::transmute::>, Vec>>(params_py); if !*STUB_WASI.get().unwrap() { static ONCE: Once = Once::new(); @@ -516,7 +516,7 @@ pub unsafe extern "C" fn componentize_py_free(ptr: *mut u8, size: usize, align: } #[export_name = "componentize-py#ToCanonBool"] -pub extern "C" fn componentize_py_to_canon_bool(_py: &Python, value: &PyAny) -> u32 { +pub extern "C" fn componentize_py_to_canon_bool(_py: &Python, value: &Bound) -> u32 { if value.is_truthy().unwrap() { 1 } else { @@ -525,27 +525,27 @@ pub extern "C" fn componentize_py_to_canon_bool(_py: &Python, value: &PyAny) -> } #[export_name = "componentize-py#ToCanonI32"] -pub extern "C" fn componentize_py_to_canon_i32(_py: &Python, value: &PyAny) -> i32 { +pub extern "C" fn componentize_py_to_canon_i32(_py: &Python, value: &Bound) -> i32 { value.extract().unwrap() } #[export_name = "componentize-py#ToCanonI64"] -pub extern "C" fn componentize_py_to_canon_i64(_py: &Python, value: &PyAny) -> i64 { +pub extern "C" fn componentize_py_to_canon_i64(_py: &Python, value: &Bound) -> i64 { value.extract().unwrap() } #[export_name = "componentize-py#ToCanonF32"] -pub extern "C" fn componentize_py_to_canon_f32(_py: &Python, value: &PyAny) -> f32 { +pub extern "C" fn componentize_py_to_canon_f32(_py: &Python, value: &Bound) -> f32 { value.extract().unwrap() } #[export_name = "componentize-py#ToCanonF64"] -pub extern "C" fn componentize_py_to_canon_f64(_py: &Python, value: &PyAny) -> f64 { +pub extern "C" fn componentize_py_to_canon_f64(_py: &Python, value: &Bound) -> f64 { value.extract().unwrap() } #[export_name = "componentize-py#ToCanonChar"] -pub extern "C" fn componentize_py_to_canon_char(_py: &Python, value: &PyAny) -> u32 { +pub extern "C" fn componentize_py_to_canon_char(_py: &Python, value: &Bound) -> u32 { let value = value.extract::().unwrap(); assert!(value.chars().count() == 1); value.chars().next().unwrap() as u32 @@ -556,7 +556,7 @@ pub extern "C" fn componentize_py_to_canon_char(_py: &Python, value: &PyAny) -> #[export_name = "componentize-py#ToCanonString"] pub unsafe extern "C" fn componentize_py_to_canon_string( _py: &Python, - value: &PyAny, + value: &Bound, destination: *mut (*const u8, usize), ) { let value = value.extract::().unwrap().into_bytes(); @@ -681,7 +681,7 @@ pub extern "C" fn componentize_py_get_field<'a>( } #[export_name = "componentize-py#GetListLength"] -pub extern "C" fn componentize_py_get_list_length(_py: &Python, value: &PyAny) -> usize { +pub extern "C" fn componentize_py_get_list_length(_py: &Python, value: &Bound) -> usize { if let Ok(bytes) = value.downcast::() { bytes.len().unwrap() } else { @@ -692,9 +692,9 @@ pub extern "C" fn componentize_py_get_list_length(_py: &Python, value: &PyAny) - #[export_name = "componentize-py#GetListElement"] pub extern "C" fn componentize_py_get_list_element<'a>( _py: &'a Python, - value: &'a PyAny, + value: &Bound<'a, PyAny>, index: usize, -) -> &'a PyAny { +) -> Bound<'a, PyAny> { value.downcast::().unwrap().get_item(index).unwrap() } @@ -911,7 +911,11 @@ pub extern "C" fn componentize_py_make_list<'a>(py: &'a Python) -> Bound<'a, PyL } #[export_name = "componentize-py#ListAppend"] -pub extern "C" fn componentize_py_list_append(_py: &Python, list: &PyList, element: &PyAny) { +pub extern "C" fn componentize_py_list_append( + _py: &Python, + list: &Bound, + element: &Bound, +) { list.append(element).unwrap(); } @@ -925,7 +929,7 @@ pub extern "C" fn componentize_py_none<'a>(py: &'a Python) -> Bound<'a, PyAny> { #[export_name = "componentize-py#GetBytes"] pub unsafe extern "C" fn componentize_py_get_bytes( _py: &Python, - src: &PyBytes, + src: &Bound, dst: *mut u8, len: usize, ) { @@ -955,7 +959,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( borrow: i32, local: i32, resource: i32, -) -> Bound { +) -> Bound<'a, PyAny> { let ty = &TYPES.get().unwrap()[usize::try_from(resource).unwrap()]; let Type::Resource { constructor, @@ -1046,7 +1050,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( #[export_name = "componentize-py#ToCanonHandle"] pub extern "C" fn componentize_py_to_canon_handle( py: &Python, - value: &PyAny, + value: Bound, borrow: i32, local: i32, resource: i32, diff --git a/src/python.rs b/src/python.rs index b8b7a38..24dd034 100644 --- a/src/python.rs +++ b/src/python.rs @@ -2,7 +2,7 @@ use { pyo3::{ exceptions::PyAssertionError, pybacked::PyBackedStr, - types::{PyAnyMethods, PyModule}, + types::{PyAnyMethods, PyModule, PyModuleMethods}, Bound, PyResult, Python, }, std::{ffi::OsString, path::PathBuf}, diff --git a/test-generator/Cargo.toml b/test-generator/Cargo.toml index 391351b..d4b4aff 100644 --- a/test-generator/Cargo.toml +++ b/test-generator/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -anyhow = "1.0.86" +anyhow = "1.0.87" getrandom = "0.2.15" hex = "0.4.3" proptest = "1.5.0" From 33806e81d794724fee5c85a37f521582aa6e8f68 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Thu, 12 Sep 2024 22:11:15 +0200 Subject: [PATCH 03/11] Revert changes to C APIs --- runtime/src/lib.rs | 175 ++++++++++++++++++++++++++------------------- src/python.rs | 4 +- 2 files changed, 105 insertions(+), 74 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 9c5e3d6..66ba1f4 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -16,7 +16,7 @@ use { PyAnyMethods, PyBool, PyBytes, PyBytesMethods, PyDict, PyList, PyListMethods, PyMapping, PyMappingMethods, PyModule, PyModuleMethods, PyString, PyTuple, }, - Borrowed, Bound, Py, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, + AsPyPointer, Bound, Py, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }, std::{ alloc::{self, Layout}, @@ -132,7 +132,7 @@ extern "C" { fn call_import<'a>( module: &'a Bound, index: u32, - params: Vec>, + params: Vec>, result_count: usize, ) -> PyResult> { let mut results = vec![MaybeUninit::<&PyAny>::uninit(); result_count]; @@ -144,10 +144,7 @@ fn call_import<'a>( index, ); - // todo: is this sound, or do we need to `.into_iter().map(MaybeUninit::assume_init).collect()` instead? - Ok(mem::transmute::>, Vec<&PyAny>>( - results, - )) + Ok(results.into_iter().map(|r| r.assume_init()).collect()) } } @@ -424,22 +421,25 @@ pub unsafe extern "C" fn componentize_py_dispatch( from_canon, ); - // todo: is this sound, or do we need to `.into_iter().map(MaybeUninit::assume_init).collect()` instead? - let params_py = mem::transmute::>, Vec>>(params_py); + let params_py = params_py + .into_iter() + .map(|p| p.assume_init()) + .map(|p| Bound::from_borrowed_ptr(py, p.as_ptr())) + .collect::>(); if !*STUB_WASI.get().unwrap() { static ONCE: Once = Once::new(); ONCE.call_once(|| { // We must call directly into the host to get the runtime environment since libc's version will only // contain the build-time pre-init snapshot. - let environ = ENVIRON.get().unwrap().bind(py); + let environ = ENVIRON.get().unwrap().bind_borrowed(py); for (k, v) in environment::get_environment() { environ.set_item(k, v).unwrap(); } // Likewise for CLI arguments. for arg in environment::get_arguments() { - ARGV.get().unwrap().bind(py).append(arg).unwrap(); + ARGV.get().unwrap().bind_borrowed(py).append(arg).unwrap(); } // Call `random.seed()` to ensure we get a fresh seed rather than the one that got baked in during @@ -476,7 +476,7 @@ pub unsafe extern "C" fn componentize_py_dispatch( if ERR_CONSTRUCTOR .get() .unwrap() - .bind(py) + .bind_borrowed(py) .eq(result.get_type_bound(py)) .unwrap() { @@ -489,7 +489,7 @@ pub unsafe extern "C" fn componentize_py_dispatch( }, }; - let result = result.into_bound(py); + let result = result.bind_borrowed(py); let result_array = [result]; componentize_py_call_indirect( @@ -516,7 +516,8 @@ pub unsafe extern "C" fn componentize_py_free(ptr: *mut u8, size: usize, align: } #[export_name = "componentize-py#ToCanonBool"] -pub extern "C" fn componentize_py_to_canon_bool(_py: &Python, value: &Bound) -> u32 { +pub extern "C" fn componentize_py_to_canon_bool(py: &Python, value: &PyAny) -> u32 { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; if value.is_truthy().unwrap() { 1 } else { @@ -525,27 +526,32 @@ pub extern "C" fn componentize_py_to_canon_bool(_py: &Python, value: &Bound) -> i32 { +pub extern "C" fn componentize_py_to_canon_i32(py: &Python, value: &PyAny) -> i32 { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; value.extract().unwrap() } #[export_name = "componentize-py#ToCanonI64"] -pub extern "C" fn componentize_py_to_canon_i64(_py: &Python, value: &Bound) -> i64 { +pub extern "C" fn componentize_py_to_canon_i64(py: &Python, value: &PyAny) -> i64 { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; value.extract().unwrap() } #[export_name = "componentize-py#ToCanonF32"] -pub extern "C" fn componentize_py_to_canon_f32(_py: &Python, value: &Bound) -> f32 { +pub extern "C" fn componentize_py_to_canon_f32(py: &Python, value: &PyAny) -> f32 { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; value.extract().unwrap() } #[export_name = "componentize-py#ToCanonF64"] -pub extern "C" fn componentize_py_to_canon_f64(_py: &Python, value: &Bound) -> f64 { +pub extern "C" fn componentize_py_to_canon_f64(py: &Python, value: &PyAny) -> f64 { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; value.extract().unwrap() } #[export_name = "componentize-py#ToCanonChar"] -pub extern "C" fn componentize_py_to_canon_char(_py: &Python, value: &Bound) -> u32 { +pub extern "C" fn componentize_py_to_canon_char(py: &Python, value: &PyAny) -> u32 { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; let value = value.extract::().unwrap(); assert!(value.chars().count() == 1); value.chars().next().unwrap() as u32 @@ -555,10 +561,11 @@ pub extern "C" fn componentize_py_to_canon_char(_py: &Python, value: &Bound, + py: &Python, + value: &PyAny, destination: *mut (*const u8, usize), ) { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; let value = value.extract::().unwrap().into_bytes(); unsafe { let result = alloc::alloc(Layout::from_size_align(value.len(), 1).unwrap()); @@ -570,10 +577,11 @@ pub unsafe extern "C" fn componentize_py_to_canon_string( #[export_name = "componentize-py#GetField"] pub extern "C" fn componentize_py_get_field<'a>( py: &'a Python, - value: Bound<'a, PyAny>, + value: &'a PyAny, ty: usize, field: usize, ) -> Bound<'a, PyAny> { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; match &TYPES.get().unwrap()[ty] { Type::Record { fields, .. } => value.getattr(fields[field].as_str()).unwrap(), Type::Variant { @@ -581,7 +589,7 @@ pub extern "C" fn componentize_py_get_field<'a>( cases, } => { let discriminant = types_to_discriminants - .bind(*py) + .bind_borrowed(*py) .get_item(value.get_type()) .unwrap(); @@ -647,7 +655,7 @@ pub extern "C" fn componentize_py_get_field<'a>( DISCRIMINANT_FIELD_INDEX => if OK_CONSTRUCTOR .get() .unwrap() - .bind(*py) + .bind_borrowed(*py) .eq(value.get_type()) .unwrap() { @@ -655,7 +663,7 @@ pub extern "C" fn componentize_py_get_field<'a>( } else if ERR_CONSTRUCTOR .get() .unwrap() - .bind(*py) + .bind_borrowed(*py) .eq(value.get_type()) .unwrap() { @@ -681,7 +689,8 @@ pub extern "C" fn componentize_py_get_field<'a>( } #[export_name = "componentize-py#GetListLength"] -pub extern "C" fn componentize_py_get_list_length(_py: &Python, value: &Bound) -> usize { +pub extern "C" fn componentize_py_get_list_length(py: &Python, value: &PyAny) -> usize { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; if let Ok(bytes) = value.downcast::() { bytes.len().unwrap() } else { @@ -691,19 +700,20 @@ pub extern "C" fn componentize_py_get_list_length(_py: &Python, value: &Bound( - _py: &'a Python, - value: &Bound<'a, PyAny>, + py: &'a Python, + value: &'a PyAny, index: usize, ) -> Bound<'a, PyAny> { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; value.downcast::().unwrap().get_item(index).unwrap() } #[export_name = "componentize-py#FromCanonBool"] -pub extern "C" fn componentize_py_from_canon_bool<'a, 'py>( - py: &'a Python<'py>, +pub extern "C" fn componentize_py_from_canon_bool<'a>( + py: &'a Python, value: u32, -) -> Borrowed<'a, 'py, PyBool> { - PyBool::new_bound(*py, value != 0) +) -> Bound<'a, PyAny> { + PyBool::new_bound(*py, value != 0).to_owned().into_any() } #[export_name = "componentize-py#FromCanonI32"] @@ -771,23 +781,27 @@ pub unsafe extern "C" fn componentize_py_from_canon_string<'a>( pub unsafe extern "C" fn componentize_py_init<'a>( py: &'a Python<'a>, ty: usize, - data: *const Bound<'a, PyAny>, + data: *const &'a PyAny, len: usize, ) -> Bound<'a, PyAny> { match &TYPES.get().unwrap()[ty] { - Type::Record { constructor, .. } => constructor - .call1( - *py, - PyTuple::new_bound(*py, slice::from_raw_parts(data, len)), - ) - .unwrap() - .into_bound(*py), + Type::Record { constructor, .. } => { + let elements = slice::from_raw_parts(data, len) + .iter() + .map(|e| Bound::from_borrowed_ptr(*py, e.as_ptr())); + constructor + .call1(*py, PyTuple::new_bound(*py, elements)) + .unwrap() + .into_bound(*py) + } Type::Variant { cases, .. } => { assert!(len == 2); - let discriminant = - ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())) - .extract::() - .unwrap(); + let discriminant = Bound::from_borrowed_ptr( + *py, + ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())).as_ptr(), + ) + .extract::() + .unwrap(); let case = &cases[usize::try_from(discriminant).unwrap()]; if case.has_payload { case.constructor.call1( @@ -804,10 +818,12 @@ pub unsafe extern "C" fn componentize_py_init<'a>( } Type::Enum { constructor, count } => { assert!(len == 2); - let discriminant = - ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())) - .extract::() - .unwrap(); + let discriminant = Bound::from_borrowed_ptr( + *py, + ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())).as_ptr(), + ) + .extract::() + .unwrap(); assert!(discriminant < *count); constructor .call1( @@ -830,7 +846,11 @@ pub unsafe extern "C" fn componentize_py_init<'a>( (BigUint::new( slice::from_raw_parts(data, len) .iter() - .map(|v| mem::transmute::(v.extract().unwrap())) + .map(|v| { + mem::transmute::( + Bound::from_borrowed_ptr(*py, v.as_ptr()).extract().unwrap(), + ) + }) .collect(), ),), ) @@ -839,24 +859,30 @@ pub unsafe extern "C" fn componentize_py_init<'a>( } Type::Option => { assert!(len == 2); - let discriminant = - ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())) - .extract::() - .unwrap(); + let discriminant = Bound::from_borrowed_ptr( + *py, + ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())).as_ptr(), + ) + .extract::() + .unwrap(); match discriminant { 0 => py.None().into_bound(*py), - 1 => ptr::read(data.offset(isize::try_from(PAYLOAD_FIELD_INDEX).unwrap())), - + 1 => Bound::from_borrowed_ptr( + *py, + ptr::read(data.offset(isize::try_from(PAYLOAD_FIELD_INDEX).unwrap())).as_ptr(), + ), _ => unreachable!(), } } Type::NestingOption => { assert!(len == 2); - let discriminant = - ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())) - .extract::() - .unwrap(); + let discriminant = Bound::from_borrowed_ptr( + *py, + ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())).as_ptr(), + ) + .extract::() + .unwrap(); match discriminant { 0 => py.None().into_bound(*py), @@ -878,10 +904,12 @@ pub unsafe extern "C" fn componentize_py_init<'a>( } Type::Result => { assert!(len == 2); - let discriminant = - ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())) - .extract::() - .unwrap(); + let discriminant = Bound::from_borrowed_ptr( + *py, + ptr::read(data.offset(isize::try_from(DISCRIMINANT_FIELD_INDEX).unwrap())).as_ptr(), + ) + .extract::() + .unwrap(); match discriminant { 0 => OK_CONSTRUCTOR.get().unwrap(), @@ -899,7 +927,10 @@ pub unsafe extern "C" fn componentize_py_init<'a>( } Type::Tuple(length) => { assert!(*length == len); - PyTuple::new_bound(*py, slice::from_raw_parts(data, len)).into_any() + let elements = slice::from_raw_parts(data, len) + .iter() + .map(|e| Bound::from_borrowed_ptr(*py, e.as_ptr())); + PyTuple::new_bound(*py, elements).into_any() } Type::Handle | Type::Resource { .. } => unreachable!(), } @@ -911,12 +942,10 @@ pub extern "C" fn componentize_py_make_list<'a>(py: &'a Python) -> Bound<'a, PyL } #[export_name = "componentize-py#ListAppend"] -pub extern "C" fn componentize_py_list_append( - _py: &Python, - list: &Bound, - element: &Bound, -) { - list.append(element).unwrap(); +pub extern "C" fn componentize_py_list_append(py: &Python, list: &PyList, element: &PyAny) { + let list = unsafe { Bound::from_borrowed_ptr(*py, list.as_ptr()) }; + let element = unsafe { Bound::from_borrowed_ptr(*py, element.as_ptr()) }; + list.downcast::().unwrap().append(element).unwrap(); } #[export_name = "componentize-py#None"] @@ -928,13 +957,15 @@ pub extern "C" fn componentize_py_none<'a>(py: &'a Python) -> Bound<'a, PyAny> { /// TODO #[export_name = "componentize-py#GetBytes"] pub unsafe extern "C" fn componentize_py_get_bytes( - _py: &Python, - src: &Bound, + py: &Python, + src: &PyBytes, dst: *mut u8, len: usize, ) { + let src = unsafe { Bound::from_borrowed_ptr(*py, src.as_ptr()) }; assert_eq!(len, src.len().unwrap()); - slice::from_raw_parts_mut(dst, len).copy_from_slice(src.as_bytes()) + slice::from_raw_parts_mut(dst, len) + .copy_from_slice(src.downcast::().unwrap().as_bytes()) } /// # Safety diff --git a/src/python.rs b/src/python.rs index 24dd034..c8504f8 100644 --- a/src/python.rs +++ b/src/python.rs @@ -26,10 +26,10 @@ fn python_componentize( Runtime::new()?.block_on(crate::componentize( wit_path.as_deref(), world, - &python_path.iter().map(|s| &**s).collect::>(), + &python_path.iter().map(|s| s.as_ref()).collect::>(), &module_worlds .iter() - .map(|(a, b)| (&**a, &**b)) + .map(|(a, b)| (a.as_ref(), b.as_ref())) .collect::>(), app_name, &output_path, From 68706e349fa70ad3df94fb8e1470762b6aedb2c4 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Thu, 12 Sep 2024 22:38:35 +0200 Subject: [PATCH 04/11] Bump min versions --- Cargo.toml | 2 +- pyproject.toml | 2 +- runtime/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7567e40..ee6fa01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ indexmap = "2.5.0" bincode = "1.3.3" heck = "0.5.0" pyo3 = { version = "0.22.2", features = [ - "abi3-py37", + "abi3-py39", "extension-module", ], optional = true } wasmtime = "24.0.0" diff --git a/pyproject.toml b/pyproject.toml index 10fa457..a751f20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["maturin>=0.15,<0.16"] +requires = ["maturin>=1.0,<2.0"] build-backend = "maturin" [tool.maturin] diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index ba59622..8627da0 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["staticlib"] anyhow = "1.0.87" once_cell = "1.19.0" pyo3 = { version = "0.22.2", features = [ - "abi3-py311", + "abi3-py312", "num-bigint", "py-clone", ] } From 5400976ad60f5f6c0391b4de3fb6481a0c61bac0 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Thu, 12 Sep 2024 22:38:54 +0200 Subject: [PATCH 05/11] Remove clone feature --- runtime/Cargo.toml | 6 +----- runtime/src/lib.rs | 10 +++++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 8627da0..277cc16 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -9,11 +9,7 @@ crate-type = ["staticlib"] [dependencies] anyhow = "1.0.87" once_cell = "1.19.0" -pyo3 = { version = "0.22.2", features = [ - "abi3-py312", - "num-bigint", - "py-clone", -] } +pyo3 = { version = "0.22.2", features = ["abi3-py312", "num-bigint"] } componentize-py-shared = { path = "../shared" } num-bigint = "0.4.6" wit-bindgen = "0.16.0" diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 66ba1f4..9baa9fb 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1003,7 +1003,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( if local != 0 { if borrow != 0 { - unsafe { PyObject::from_borrowed_ptr(*py, value as usize as _) }.into_bound(*py) + unsafe { Bound::from_borrowed_ptr(*py, value as usize as _) } } else { let Some(LocalResource { rep, .. }) = resource_local else { panic!("expected local resource, found {ty:?}"); @@ -1023,7 +1023,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( } }; - let value = unsafe { PyObject::from_borrowed_ptr(*py, rep as _) }.into_bound(*py); + let value = unsafe { Bound::from_borrowed_ptr(*py, rep as _) }; value .delattr(intern!(*py, "__componentize_py_handle")) @@ -1053,7 +1053,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( let handle = value.to_object(*py); instance - .setattr(*py, intern!(*py, "handle"), handle.clone()) + .setattr(*py, intern!(*py, "handle"), handle.clone_ref(*py)) .unwrap(); let finalizer = FINALIZE @@ -1062,7 +1062,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( .call1( *py, ( - instance.clone(), + instance.clone_ref(*py), DROP_RESOURCE.get().unwrap(), drop.to_object(*py), handle, @@ -1125,7 +1125,7 @@ pub extern "C" fn componentize_py_to_canon_handle( .call1( *py, ( - instance.clone(), + instance.clone_ref(*py), DROP_RESOURCE.get().unwrap(), drop.to_object(*py), handle, From 4fd7e1fe01356985f888461c2b0d76bac2b9eda4 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Thu, 12 Sep 2024 22:55:15 +0200 Subject: [PATCH 06/11] Use downcast_into instead of extract --- runtime/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 9baa9fb..0ee0f2c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -326,7 +326,7 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { let environ = py .import_bound("os")? .getattr("environ")? - .extract::>() + .downcast_into::() .unwrap(); let keys = environ.keys()?; @@ -355,7 +355,7 @@ fn do_init(app_name: String, symbols: Symbols, stub_wasi: bool) -> Result<()> { let argv = py .import_bound("sys")? .getattr("argv")? - .extract::>() + .downcast_into::() .unwrap(); for i in 0..argv.len() { From 81aadf308898d15cde497314f7a692eb335a8787 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Thu, 12 Sep 2024 23:06:16 +0200 Subject: [PATCH 07/11] Cleanup unnecessary extracts --- runtime/src/lib.rs | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 0ee0f2c..208100d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -421,12 +421,6 @@ pub unsafe extern "C" fn componentize_py_dispatch( from_canon, ); - let params_py = params_py - .into_iter() - .map(|p| p.assume_init()) - .map(|p| Bound::from_borrowed_ptr(py, p.as_ptr())) - .collect::>(); - if !*STUB_WASI.get().unwrap() { static ONCE: Once = Once::new(); ONCE.call_once(|| { @@ -449,13 +443,20 @@ pub unsafe extern "C" fn componentize_py_dispatch( } let export = &EXPORTS.get().unwrap()[export]; + + let mut params_py = params_py + .into_iter() + .map(|p| Bound::from_borrowed_ptr(py, p.assume_init().as_ptr())); let result = match export { Export::Freestanding { instance, name } => { instance.call_method1(py, name.bind(py), PyTuple::new_bound(py, params_py)) } Export::Constructor(class) => class.call1(py, PyTuple::new_bound(py, params_py)), - Export::Method(name) => params_py[0] - .call_method1(name.bind(py), PyTuple::new_bound(py, ¶ms_py[1..])) + Export::Method(name) => params_py + // Call method on self with remaining iterator elements + .next() + .unwrap() + .call_method1(name.bind(py), PyTuple::new_bound(py, params_py)) .map(|r| r.into()), Export::Static { class, name } => class .getattr(py, name.bind(py)) @@ -624,24 +625,18 @@ pub extern "C" fn componentize_py_get_field<'a>( unsafe { mem::transmute::(value) } .to_object(*py) .into_bound(*py) - .extract() - .unwrap() } Type::Option => match i32::try_from(field).unwrap() { DISCRIMINANT_FIELD_INDEX => if value.is_none() { 0 } else { 1 } .to_object(*py) - .into_bound(*py) - .extract() - .unwrap(), + .into_bound(*py), PAYLOAD_FIELD_INDEX => value, _ => unreachable!(), }, Type::NestingOption => match i32::try_from(field).unwrap() { DISCRIMINANT_FIELD_INDEX => if value.is_none() { 0 } else { 1 } .to_object(*py) - .into_bound(*py) - .extract() - .unwrap(), + .into_bound(*py), PAYLOAD_FIELD_INDEX => { if value.is_none() { value @@ -721,7 +716,7 @@ pub extern "C" fn componentize_py_from_canon_i32<'a>( py: &'a Python<'a>, value: i32, ) -> Bound<'a, PyAny> { - value.to_object(*py).into_bound(*py).extract().unwrap() + value.to_object(*py).into_bound(*py) } #[export_name = "componentize-py#FromCanonI64"] @@ -729,7 +724,7 @@ pub extern "C" fn componentize_py_from_canon_i64<'a>( py: &'a Python<'a>, value: i64, ) -> Bound<'a, PyAny> { - value.to_object(*py).into_bound(*py).extract().unwrap() + value.to_object(*py).into_bound(*py) } #[export_name = "componentize-py#FromCanonF32"] @@ -737,7 +732,7 @@ pub extern "C" fn componentize_py_from_canon_f32<'a>( py: &'a Python<'a>, value: f32, ) -> Bound<'a, PyAny> { - value.to_object(*py).into_bound(*py).extract().unwrap() + value.to_object(*py).into_bound(*py) } #[export_name = "componentize-py#FromCanonF64"] @@ -745,7 +740,7 @@ pub extern "C" fn componentize_py_from_canon_f64<'a>( py: &'a Python<'a>, value: f64, ) -> Bound<'a, PyAny> { - value.to_object(*py).into_bound(*py).extract().unwrap() + value.to_object(*py).into_bound(*py) } #[export_name = "componentize-py#FromCanonChar"] @@ -758,8 +753,6 @@ pub extern "C" fn componentize_py_from_canon_char<'a>( .to_string() .to_object(*py) .into_bound(*py) - .extract() - .unwrap() } /// # Safety From 77b8038670366202355f081584a5db82cbdd482f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 13 Sep 2024 09:52:59 -0600 Subject: [PATCH 08/11] remove obsolete `dl` module Signed-off-by: Joel Dice --- runtime/src/lib.rs | 173 --------------------------------------------- src/lib.rs | 4 +- 2 files changed, 3 insertions(+), 174 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 208100d..c31e94b 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1149,179 +1149,6 @@ pub extern "C" fn componentize_py_to_canon_handle( } } -// TODO: Update to the latest `wit-component`, which has a `use_built_in_libdl` option that makes the following -// unecessary: -pub mod dl { - use std::{ - ffi::{c_char, c_int, c_void, CStr}, - ptr, slice, - }; - - const RTLD_LAZY: c_int = 1; - const RTLD_NOW: c_int = 2; - - const RTLD_NEXT: isize = -1; - const RTLD_DEFAULT: isize = 0; - - #[repr(C)] - pub struct Name { - length: u32, - data: *const u8, - } - - #[repr(C)] - pub struct Symbol { - name: Name, - address: *const c_void, - } - - #[repr(C)] - pub struct Symbols { - count: u32, - symbols: *const Symbol, - } - - #[repr(C)] - pub struct Library { - name: Name, - symbols: Symbols, - } - - #[repr(C)] - pub struct Libraries { - count: u32, - libraries: *const Library, - } - - struct Pointer(*const T); - - unsafe impl Sync for Pointer {} - - static mut ERROR: Pointer = Pointer(ptr::null()); - static mut LIBRARIES: Pointer = Pointer(ptr::null()); - - unsafe fn invalid_handle(library: *const c_void) -> bool { - if LIBRARIES.0.is_null() { - panic!( - "`__wasm_set_libraries` should have been called during \ - instantiation with a non-NULL value" - ); - } - - let library = library as *const Library; - if (0..(*LIBRARIES.0).count).any(|index| { - (*LIBRARIES.0) - .libraries - .add(usize::try_from(index).unwrap()) - == library - }) { - false - } else { - ERROR.0 = b"invalid library handle\0" as *const _ as _; - true - } - } - - /// # Safety - /// TODO - #[no_mangle] - pub unsafe extern "C" fn dlclose(library: *mut c_void) -> c_int { - if invalid_handle(library) { - -1 - } else { - 0 - } - } - - /// # Safety - /// TODO - #[no_mangle] - pub unsafe extern "C" fn dlerror() -> *const c_char { - let value = ERROR.0; - ERROR.0 = ptr::null(); - value - } - - /// # Safety - /// TODO - #[no_mangle] - pub unsafe extern "C" fn dlopen(name: *const c_char, flags: c_int) -> *const c_void { - if LIBRARIES.0.is_null() { - panic!( - "`__wasm_set_libraries` should have been called during \ - instantiation with a non-NULL value" - ); - } - - if (flags & !(RTLD_LAZY | RTLD_NOW)) != 0 { - // TODO - ERROR.0 = b"dlopen flags not yet supported\0" as *const _ as _; - return ptr::null(); - } - - let name = CStr::from_ptr(name); - let name = name.to_bytes(); - let libraries = slice::from_raw_parts( - (*LIBRARIES.0).libraries, - usize::try_from((*LIBRARIES.0).count).unwrap(), - ); - if let Ok(index) = libraries.binary_search_by(|library| { - slice::from_raw_parts( - library.name.data, - usize::try_from(library.name.length).unwrap(), - ) - .cmp(name) - }) { - &libraries[index] as *const _ as _ - } else { - ERROR.0 = "library not found\0" as *const _ as _; - ptr::null() - } - } - - /// # Safety - /// TODO - #[no_mangle] - pub unsafe extern "C" fn dlsym(library: *const c_void, name: *const c_char) -> *const c_void { - if library as isize == RTLD_NEXT || library as isize == RTLD_DEFAULT { - // TODO - ERROR.0 = "dlsym RTLD_NEXT and RTLD_DEFAULT not yet supported\0" as *const _ as _; - return ptr::null(); - } - - if invalid_handle(library) { - return ptr::null(); - } - - let library = library as *const Library; - let name = CStr::from_ptr(name); - let name = name.to_bytes(); - let symbols = slice::from_raw_parts( - (*library).symbols.symbols, - usize::try_from((*library).symbols.count).unwrap(), - ); - if let Ok(index) = symbols.binary_search_by(|symbol| { - slice::from_raw_parts( - symbol.name.data, - usize::try_from(symbol.name.length).unwrap(), - ) - .cmp(name) - }) { - symbols[index].address - } else { - ERROR.0 = "library not found\0" as *const _ as _; - ptr::null() - } - } - - /// # Safety - /// TODO - #[no_mangle] - pub unsafe extern "C" fn __wasm_set_libraries(libraries: *const Libraries) { - LIBRARIES.0 = libraries; - } -} - // As of this writing, recent Rust `nightly` builds include a version of the `libc` crate that expects `wasi-libc` // to define the following global variables, but `wasi-libc` defines them as preprocessor constants which aren't // visible at link time, so we need to define them somewhere. Ideally, we should fix this upstream, but for now we diff --git a/src/lib.rs b/src/lib.rs index b1eb179..a2c458c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -445,7 +445,9 @@ pub async fn componentize( } // Link all the libraries (including any native extensions) into a single component. - let mut linker = wit_component::Linker::default().validate(true); + let mut linker = wit_component::Linker::default() + .validate(true) + .use_built_in_libdl(true); let mut wasi_imports = HashMap::new(); for Library { From 6a66ae9584160cc3ea5b9955e1fb3fc1c7b879fb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 13 Sep 2024 09:53:49 -0600 Subject: [PATCH 09/11] fix resource test regressions Py03 0.22.x no longer has `Py::into_ref`, which returned a reference that was guaranteed to survive until the GIL was released. We were relying on that to ensure borrow handles were released before returning to the caller. Since there's no equivalent feature in 0.22.x AFAICT, we need to clean up borrow handles ourselves. This also fixes `componentize_py_to_canon_handle`, which was causing reference counts to be decremented too early. Note that, although the tests are now passing, there may still be leaks due to reference counts not being decremented where they should. Not sure what the best way to test that might be; we might need to research Python tools for heap profiling and leak detection. Finally, I haven't tested the examples yet; we'll want to do that before we merge any of this into main. Signed-off-by: Joel Dice --- Cargo.toml | 1 + runtime/src/lib.rs | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ee6fa01..78786e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,4 @@ test-generator = { path = "test-generator" } [workspace] members = ["runtime", "shared", "test-generator"] + diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index c31e94b..8a07300 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -22,8 +22,9 @@ use { alloc::{self, Layout}, ffi::c_void, mem::{self, MaybeUninit}, + ops::DerefMut, ptr, slice, str, - sync::Once, + sync::{Mutex, Once}, }, wasi::cli::environment, }; @@ -48,6 +49,13 @@ static DROP_RESOURCE: OnceCell = OnceCell::new(); static SEED: OnceCell = OnceCell::new(); static ARGV: OnceCell> = OnceCell::new(); +struct Borrow { + handle: i32, + drop: u32, +} + +static BORROWS: Mutex> = Mutex::new(Vec::new()); + const DISCRIMINANT_FIELD_INDEX: i32 = 0; const PAYLOAD_FIELD_INDEX: i32 = 1; @@ -499,6 +507,19 @@ pub unsafe extern "C" fn componentize_py_dispatch( results_canon, to_canon, ); + + let borrows = mem::take(BORROWS.lock().unwrap().deref_mut()); + for Borrow { handle, drop } in borrows { + let params = [handle]; + unsafe { + componentize_py_call_indirect( + &py as *const _ as _, + params.as_ptr() as _, + ptr::null_mut(), + drop, + ); + } + } }); } @@ -1035,6 +1056,13 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( panic!("expected remote resource, found {ty:?}"); }; + if borrow != 0 { + BORROWS.lock().unwrap().push(Borrow { + handle: value, + drop: *drop, + }); + } + let instance = constructor .call_method1( *py, @@ -1074,11 +1102,12 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( #[export_name = "componentize-py#ToCanonHandle"] pub extern "C" fn componentize_py_to_canon_handle( py: &Python, - value: Bound, + value: &PyAny, borrow: i32, local: i32, resource: i32, ) -> u32 { + let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; if local != 0 { let ty = &TYPES.get().unwrap()[usize::try_from(resource).unwrap()]; let Type::Resource { From 6f65b695dcb44f7f5df6eb66a6e4bce13859f7a6 Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Fri, 13 Sep 2024 21:41:25 +0200 Subject: [PATCH 10/11] Revert assume_init() implementations --- runtime/src/lib.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8a07300..67244ee 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -152,7 +152,10 @@ fn call_import<'a>( index, ); - Ok(results.into_iter().map(|r| r.assume_init()).collect()) + // todo: is this sound, or do we need to `.into_iter().map(MaybeUninit::assume_init).collect()` instead? + Ok(mem::transmute::>, Vec<&PyAny>>( + results, + )) } } @@ -452,9 +455,10 @@ pub unsafe extern "C" fn componentize_py_dispatch( let export = &EXPORTS.get().unwrap()[export]; - let mut params_py = params_py + // todo: is this sound, or do we need to `.into_iter().map(MaybeUninit::assume_init).collect()` instead? + let mut params_py = mem::transmute::>, Vec<&PyAny>>(params_py) .into_iter() - .map(|p| Bound::from_borrowed_ptr(py, p.assume_init().as_ptr())); + .map(|p| Bound::from_borrowed_ptr(py, p.as_ptr())); let result = match export { Export::Freestanding { instance, name } => { instance.call_method1(py, name.bind(py), PyTuple::new_bound(py, params_py)) From f86dcd0a325dcfe45eec7f86fbe1211935b4a20d Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Fri, 13 Sep 2024 23:42:40 +0200 Subject: [PATCH 11/11] Always return Py instead of Bound objects It felt strange that the C apis were all returning objects with lifetimes. This updates everything that returned a Bound to always return a Py, which seems safer, and is also closer to what the WASM side expects (even though currently they are laid out in memory the same). --- runtime/src/lib.rs | 268 ++++++++++++++++++++++----------------------- 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 67244ee..d688b64 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -461,17 +461,17 @@ pub unsafe extern "C" fn componentize_py_dispatch( .map(|p| Bound::from_borrowed_ptr(py, p.as_ptr())); let result = match export { Export::Freestanding { instance, name } => { - instance.call_method1(py, name.bind(py), PyTuple::new_bound(py, params_py)) + instance.call_method1(py, name, PyTuple::new_bound(py, params_py)) } Export::Constructor(class) => class.call1(py, PyTuple::new_bound(py, params_py)), Export::Method(name) => params_py // Call method on self with remaining iterator elements .next() .unwrap() - .call_method1(name.bind(py), PyTuple::new_bound(py, params_py)) + .call_method1(name, PyTuple::new_bound(py, params_py)) .map(|r| r.into()), Export::Static { class, name } => class - .getattr(py, name.bind(py)) + .getattr(py, name) .and_then(|function| function.call1(py, PyTuple::new_bound(py, params_py))), }; @@ -502,7 +502,6 @@ pub unsafe extern "C" fn componentize_py_dispatch( }, }; - let result = result.bind_borrowed(py); let result_array = [result]; componentize_py_call_indirect( @@ -541,9 +540,11 @@ pub unsafe extern "C" fn componentize_py_free(ptr: *mut u8, size: usize, align: alloc::dealloc(ptr, Layout::from_size_align(size, align).unwrap()) } +/// # Safety +/// TODO #[export_name = "componentize-py#ToCanonBool"] -pub extern "C" fn componentize_py_to_canon_bool(py: &Python, value: &PyAny) -> u32 { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; +pub unsafe extern "C" fn componentize_py_to_canon_bool(py: &Python, value: &PyAny) -> u32 { + let value = Bound::from_borrowed_ptr(*py, value.as_ptr()); if value.is_truthy().unwrap() { 1 } else { @@ -551,34 +552,49 @@ pub extern "C" fn componentize_py_to_canon_bool(py: &Python, value: &PyAny) -> u } } +/// # Safety +/// TODO #[export_name = "componentize-py#ToCanonI32"] -pub extern "C" fn componentize_py_to_canon_i32(py: &Python, value: &PyAny) -> i32 { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; - value.extract().unwrap() +pub unsafe extern "C" fn componentize_py_to_canon_i32(py: &Python, value: &PyAny) -> i32 { + Bound::from_borrowed_ptr(*py, value.as_ptr()) + .extract() + .unwrap() } +/// # Safety +/// TODO #[export_name = "componentize-py#ToCanonI64"] -pub extern "C" fn componentize_py_to_canon_i64(py: &Python, value: &PyAny) -> i64 { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; - value.extract().unwrap() +pub unsafe extern "C" fn componentize_py_to_canon_i64(py: &Python, value: &PyAny) -> i64 { + Bound::from_borrowed_ptr(*py, value.as_ptr()) + .extract() + .unwrap() } +/// # Safety +/// TODO #[export_name = "componentize-py#ToCanonF32"] -pub extern "C" fn componentize_py_to_canon_f32(py: &Python, value: &PyAny) -> f32 { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; - value.extract().unwrap() +pub unsafe extern "C" fn componentize_py_to_canon_f32(py: &Python, value: &PyAny) -> f32 { + Bound::from_borrowed_ptr(*py, value.as_ptr()) + .extract() + .unwrap() } +/// # Safety +/// TODO #[export_name = "componentize-py#ToCanonF64"] -pub extern "C" fn componentize_py_to_canon_f64(py: &Python, value: &PyAny) -> f64 { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; - value.extract().unwrap() +pub unsafe extern "C" fn componentize_py_to_canon_f64(py: &Python, value: &PyAny) -> f64 { + Bound::from_borrowed_ptr(*py, value.as_ptr()) + .extract() + .unwrap() } +/// # Safety +/// TODO #[export_name = "componentize-py#ToCanonChar"] -pub extern "C" fn componentize_py_to_canon_char(py: &Python, value: &PyAny) -> u32 { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; - let value = value.extract::().unwrap(); +pub unsafe extern "C" fn componentize_py_to_canon_char(py: &Python, value: &PyAny) -> u32 { + let value = Bound::from_borrowed_ptr(*py, value.as_ptr()) + .extract::() + .unwrap(); assert!(value.chars().count() == 1); value.chars().next().unwrap() as u32 } @@ -591,49 +607,52 @@ pub unsafe extern "C" fn componentize_py_to_canon_string( value: &PyAny, destination: *mut (*const u8, usize), ) { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; - let value = value.extract::().unwrap().into_bytes(); - unsafe { - let result = alloc::alloc(Layout::from_size_align(value.len(), 1).unwrap()); - ptr::copy_nonoverlapping(value.as_ptr(), result, value.len()); - destination.write((result, value.len())); - } + let value = Bound::from_borrowed_ptr(*py, value.as_ptr()) + .extract::() + .unwrap() + .into_bytes(); + + let result = alloc::alloc(Layout::from_size_align(value.len(), 1).unwrap()); + ptr::copy_nonoverlapping(value.as_ptr(), result, value.len()); + destination.write((result, value.len())); } +/// # Safety +/// TODO #[export_name = "componentize-py#GetField"] -pub extern "C" fn componentize_py_get_field<'a>( - py: &'a Python, - value: &'a PyAny, +pub unsafe extern "C" fn componentize_py_get_field( + py: &Python, + value: &PyAny, ty: usize, field: usize, -) -> Bound<'a, PyAny> { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; +) -> Py { + let value = Bound::from_borrowed_ptr(*py, value.as_ptr()); match &TYPES.get().unwrap()[ty] { - Type::Record { fields, .. } => value.getattr(fields[field].as_str()).unwrap(), + Type::Record { fields, .. } => value.getattr(fields[field].as_str()).unwrap().unbind(), Type::Variant { types_to_discriminants, cases, } => { let discriminant = types_to_discriminants - .bind_borrowed(*py) + .bind(*py) .get_item(value.get_type()) .unwrap(); match i32::try_from(field).unwrap() { - DISCRIMINANT_FIELD_INDEX => discriminant, + DISCRIMINANT_FIELD_INDEX => discriminant.unbind(), PAYLOAD_FIELD_INDEX => { if cases[discriminant.extract::().unwrap()].has_payload { - value.getattr("value").unwrap() + value.getattr("value").unwrap().unbind() } else { - py.None().into_bound(*py) + py.None() } } _ => unreachable!(), } } Type::Enum { .. } => match i32::try_from(field).unwrap() { - DISCRIMINANT_FIELD_INDEX => value.getattr("value").unwrap(), - PAYLOAD_FIELD_INDEX => py.None().into_bound(*py), + DISCRIMINANT_FIELD_INDEX => value.getattr("value").unwrap().unbind(), + PAYLOAD_FIELD_INDEX => py.None(), _ => unreachable!(), }, Type::Flags { u32_count, .. } => { @@ -647,26 +666,20 @@ pub extern "C" fn componentize_py_get_field<'a>( .nth(field) .unwrap_or(0); - unsafe { mem::transmute::(value) } - .to_object(*py) - .into_bound(*py) + unsafe { mem::transmute::(value) }.to_object(*py) } Type::Option => match i32::try_from(field).unwrap() { - DISCRIMINANT_FIELD_INDEX => if value.is_none() { 0 } else { 1 } - .to_object(*py) - .into_bound(*py), - PAYLOAD_FIELD_INDEX => value, + DISCRIMINANT_FIELD_INDEX => if value.is_none() { 0 } else { 1 }.to_object(*py), + PAYLOAD_FIELD_INDEX => value.unbind(), _ => unreachable!(), }, Type::NestingOption => match i32::try_from(field).unwrap() { - DISCRIMINANT_FIELD_INDEX => if value.is_none() { 0 } else { 1 } - .to_object(*py) - .into_bound(*py), + DISCRIMINANT_FIELD_INDEX => if value.is_none() { 0 } else { 1 }.to_object(*py), PAYLOAD_FIELD_INDEX => { if value.is_none() { - value + value.unbind() } else { - value.getattr("value").unwrap() + value.getattr("value").unwrap().unbind() } } _ => unreachable!(), @@ -691,9 +704,8 @@ pub extern "C" fn componentize_py_get_field<'a>( } else { unreachable!() } - .to_object(*py) - .into_bound(*py), - PAYLOAD_FIELD_INDEX => value.getattr("value").unwrap(), + .to_object(*py), + PAYLOAD_FIELD_INDEX => value.getattr("value").unwrap().unbind(), _ => unreachable!(), }, Type::Tuple(length) => { @@ -703,14 +715,17 @@ pub extern "C" fn componentize_py_get_field<'a>( .unwrap() .get_item(field) .unwrap() + .unbind() } Type::Handle | Type::Resource { .. } => unreachable!(), } } +/// # Safety +/// TODO #[export_name = "componentize-py#GetListLength"] -pub extern "C" fn componentize_py_get_list_length(py: &Python, value: &PyAny) -> usize { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; +pub unsafe extern "C" fn componentize_py_get_list_length(py: &Python, value: &PyAny) -> usize { + let value = Bound::from_borrowed_ptr(*py, value.as_ptr()); if let Ok(bytes) = value.downcast::() { bytes.len().unwrap() } else { @@ -718,90 +733,76 @@ pub extern "C" fn componentize_py_get_list_length(py: &Python, value: &PyAny) -> } } +/// # Safety +/// TODO #[export_name = "componentize-py#GetListElement"] -pub extern "C" fn componentize_py_get_list_element<'a>( - py: &'a Python, - value: &'a PyAny, +pub unsafe extern "C" fn componentize_py_get_list_element( + py: &Python, + value: &PyAny, index: usize, -) -> Bound<'a, PyAny> { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; - value.downcast::().unwrap().get_item(index).unwrap() +) -> Py { + let value = Bound::from_borrowed_ptr(*py, value.as_ptr()); + value + .downcast::() + .unwrap() + .get_item(index) + .unwrap() + .unbind() } #[export_name = "componentize-py#FromCanonBool"] -pub extern "C" fn componentize_py_from_canon_bool<'a>( - py: &'a Python, - value: u32, -) -> Bound<'a, PyAny> { - PyBool::new_bound(*py, value != 0).to_owned().into_any() +pub extern "C" fn componentize_py_from_canon_bool(py: &Python, value: u32) -> Py { + PyBool::new_bound(*py, value != 0).to_owned().unbind() } #[export_name = "componentize-py#FromCanonI32"] -pub extern "C" fn componentize_py_from_canon_i32<'a>( - py: &'a Python<'a>, - value: i32, -) -> Bound<'a, PyAny> { - value.to_object(*py).into_bound(*py) +pub extern "C" fn componentize_py_from_canon_i32(py: &Python, value: i32) -> Py { + value.to_object(*py) } #[export_name = "componentize-py#FromCanonI64"] -pub extern "C" fn componentize_py_from_canon_i64<'a>( - py: &'a Python<'a>, - value: i64, -) -> Bound<'a, PyAny> { - value.to_object(*py).into_bound(*py) +pub extern "C" fn componentize_py_from_canon_i64(py: &Python, value: i64) -> Py { + value.to_object(*py) } #[export_name = "componentize-py#FromCanonF32"] -pub extern "C" fn componentize_py_from_canon_f32<'a>( - py: &'a Python<'a>, - value: f32, -) -> Bound<'a, PyAny> { - value.to_object(*py).into_bound(*py) +pub extern "C" fn componentize_py_from_canon_f32(py: &Python, value: f32) -> Py { + value.to_object(*py) } #[export_name = "componentize-py#FromCanonF64"] -pub extern "C" fn componentize_py_from_canon_f64<'a>( - py: &'a Python<'a>, - value: f64, -) -> Bound<'a, PyAny> { - value.to_object(*py).into_bound(*py) +pub extern "C" fn componentize_py_from_canon_f64(py: &Python, value: f64) -> Py { + value.to_object(*py) } #[export_name = "componentize-py#FromCanonChar"] -pub extern "C" fn componentize_py_from_canon_char<'a>( - py: &'a Python<'a>, - value: u32, -) -> Bound<'a, PyAny> { - char::from_u32(value) - .unwrap() - .to_string() - .to_object(*py) - .into_bound(*py) +pub extern "C" fn componentize_py_from_canon_char(py: &Python, value: u32) -> Py { + char::from_u32(value).unwrap().to_string().to_object(*py) } /// # Safety /// TODO #[export_name = "componentize-py#FromCanonString"] -pub unsafe extern "C" fn componentize_py_from_canon_string<'a>( - py: &'a Python, +pub unsafe extern "C" fn componentize_py_from_canon_string( + py: &Python, data: *const u8, len: usize, -) -> Bound<'a, PyString> { +) -> Py { PyString::new_bound(*py, unsafe { str::from_utf8_unchecked(slice::from_raw_parts(data, len)) }) + .unbind() } /// # Safety /// TODO #[export_name = "componentize-py#Init"] -pub unsafe extern "C" fn componentize_py_init<'a>( - py: &'a Python<'a>, +pub unsafe extern "C" fn componentize_py_init( + py: &Python, ty: usize, - data: *const &'a PyAny, + data: *const &PyAny, len: usize, -) -> Bound<'a, PyAny> { +) -> Py { match &TYPES.get().unwrap()[ty] { Type::Record { constructor, .. } => { let elements = slice::from_raw_parts(data, len) @@ -810,7 +811,6 @@ pub unsafe extern "C" fn componentize_py_init<'a>( constructor .call1(*py, PyTuple::new_bound(*py, elements)) .unwrap() - .into_bound(*py) } Type::Variant { cases, .. } => { assert!(len == 2); @@ -832,7 +832,6 @@ pub unsafe extern "C" fn componentize_py_init<'a>( case.constructor.call1(*py, ()) } .unwrap() - .into_bound(*py) } Type::Enum { constructor, count } => { assert!(len == 2); @@ -851,7 +850,6 @@ pub unsafe extern "C" fn componentize_py_init<'a>( )),), ) .unwrap() - .into_bound(*py) } Type::Flags { constructor, @@ -873,7 +871,6 @@ pub unsafe extern "C" fn componentize_py_init<'a>( ),), ) .unwrap() - .into_bound(*py) } Type::Option => { assert!(len == 2); @@ -885,8 +882,8 @@ pub unsafe extern "C" fn componentize_py_init<'a>( .unwrap(); match discriminant { - 0 => py.None().into_bound(*py), - 1 => Bound::from_borrowed_ptr( + 0 => py.None(), + 1 => Py::from_borrowed_ptr( *py, ptr::read(data.offset(isize::try_from(PAYLOAD_FIELD_INDEX).unwrap())).as_ptr(), ), @@ -903,7 +900,7 @@ pub unsafe extern "C" fn componentize_py_init<'a>( .unwrap(); match discriminant { - 0 => py.None().into_bound(*py), + 0 => py.None(), 1 => SOME_CONSTRUCTOR .get() @@ -914,8 +911,7 @@ pub unsafe extern "C" fn componentize_py_init<'a>( data.offset(isize::try_from(PAYLOAD_FIELD_INDEX).unwrap()), ),), ) - .unwrap() - .into_bound(*py), + .unwrap(), _ => unreachable!(), } @@ -941,34 +937,35 @@ pub unsafe extern "C" fn componentize_py_init<'a>( ),), ) .unwrap() - .into_bound(*py) } Type::Tuple(length) => { assert!(*length == len); let elements = slice::from_raw_parts(data, len) .iter() .map(|e| Bound::from_borrowed_ptr(*py, e.as_ptr())); - PyTuple::new_bound(*py, elements).into_any() + PyTuple::new_bound(*py, elements).into_any().unbind() } Type::Handle | Type::Resource { .. } => unreachable!(), } } #[export_name = "componentize-py#MakeList"] -pub extern "C" fn componentize_py_make_list<'a>(py: &'a Python) -> Bound<'a, PyList> { - PyList::empty_bound(*py) +pub extern "C" fn componentize_py_make_list(py: &Python) -> Py { + PyList::empty_bound(*py).unbind() } +/// # Safety +/// TODO #[export_name = "componentize-py#ListAppend"] -pub extern "C" fn componentize_py_list_append(py: &Python, list: &PyList, element: &PyAny) { - let list = unsafe { Bound::from_borrowed_ptr(*py, list.as_ptr()) }; - let element = unsafe { Bound::from_borrowed_ptr(*py, element.as_ptr()) }; +pub unsafe extern "C" fn componentize_py_list_append(py: &Python, list: &PyList, element: &PyAny) { + let list = Bound::from_borrowed_ptr(*py, list.as_ptr()); + let element = Bound::from_borrowed_ptr(*py, element.as_ptr()); list.downcast::().unwrap().append(element).unwrap(); } #[export_name = "componentize-py#None"] -pub extern "C" fn componentize_py_none<'a>(py: &'a Python) -> Bound<'a, PyAny> { - py.None().into_bound(*py) +pub extern "C" fn componentize_py_none(py: &Python) -> Py { + py.None() } /// # Safety @@ -980,7 +977,7 @@ pub unsafe extern "C" fn componentize_py_get_bytes( dst: *mut u8, len: usize, ) { - let src = unsafe { Bound::from_borrowed_ptr(*py, src.as_ptr()) }; + let src = Bound::from_borrowed_ptr(*py, src.as_ptr()); assert_eq!(len, src.len().unwrap()); slice::from_raw_parts_mut(dst, len) .copy_from_slice(src.downcast::().unwrap().as_bytes()) @@ -989,26 +986,27 @@ pub unsafe extern "C" fn componentize_py_get_bytes( /// # Safety /// TODO #[export_name = "componentize-py#MakeBytes"] -pub unsafe extern "C" fn componentize_py_make_bytes<'a>( - py: &'a Python, +pub unsafe extern "C" fn componentize_py_make_bytes( + py: &Python, src: *const u8, len: usize, -) -> Bound<'a, PyBytes> { +) -> Py { PyBytes::new_bound_with(*py, len, |dst| { dst.copy_from_slice(slice::from_raw_parts(src, len)); Ok(()) }) .unwrap() + .unbind() } #[export_name = "componentize-py#FromCanonHandle"] -pub extern "C" fn componentize_py_from_canon_handle<'a>( - py: &'a Python<'a>, +pub extern "C" fn componentize_py_from_canon_handle( + py: &Python, value: i32, borrow: i32, local: i32, resource: i32, -) -> Bound<'a, PyAny> { +) -> Py { let ty = &TYPES.get().unwrap()[usize::try_from(resource).unwrap()]; let Type::Resource { constructor, @@ -1021,7 +1019,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( if local != 0 { if borrow != 0 { - unsafe { Bound::from_borrowed_ptr(*py, value as usize as _) } + unsafe { Py::from_borrowed_ptr(*py, value as usize as _) } } else { let Some(LocalResource { rep, .. }) = resource_local else { panic!("expected local resource, found {ty:?}"); @@ -1053,7 +1051,7 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( .call_method0(intern!(*py, "detach")) .unwrap(); - value + value.unbind() } } else { let Some(RemoteResource { drop }) = resource_remote else { @@ -1099,19 +1097,21 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( .setattr(*py, intern!(*py, "finalizer"), finalizer) .unwrap(); - instance.into_bound(*py) + instance } } +/// # Safety +/// TODO #[export_name = "componentize-py#ToCanonHandle"] -pub extern "C" fn componentize_py_to_canon_handle( +pub unsafe extern "C" fn componentize_py_to_canon_handle( py: &Python, value: &PyAny, borrow: i32, local: i32, resource: i32, ) -> u32 { - let value = unsafe { Bound::from_borrowed_ptr(*py, value.as_ptr()) }; + let value = Bound::from_borrowed_ptr(*py, value.as_ptr()); if local != 0 { let ty = &TYPES.get().unwrap()[usize::try_from(resource).unwrap()]; let Type::Resource {