diff --git a/Cargo.lock b/Cargo.lock index d2d40b3..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.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233" +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.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" +checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8" dependencies = [ "once_cell", "target-lexicon", @@ -1488,9 +1455,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa" +checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6" dependencies = [ "libc", "pyo3-build-config", @@ -1498,9 +1465,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158" +checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -1510,11 +1477,11 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.20.3" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185" +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 0d27fc5..78786e7 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,8 +22,8 @@ wasmparser = "0.216.0" indexmap = "2.5.0" bincode = "1.3.3" heck = "0.5.0" -pyo3 = { version = "0.20.0", features = [ - "abi3-py37", +pyo3 = { version = "0.22.2", features = [ + "abi3-py39", "extension-module", ], optional = true } wasmtime = "24.0.0" @@ -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" @@ -61,3 +61,4 @@ test-generator = { path = "test-generator" } [workspace] members = ["runtime", "shared", "test-generator"] + 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 91edd8f..277cc16 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" crate-type = ["staticlib"] [dependencies] -anyhow = "1.0.86" +anyhow = "1.0.87" once_cell = "1.19.0" -pyo3 = { version = "0.20.0", features = ["abi3-py311", "num-bigint"] } +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 fb32a5b..d688b64 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -12,15 +12,19 @@ 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, PyBytesMethods, PyDict, PyList, PyListMethods, + PyMapping, PyMappingMethods, PyModule, PyModuleMethods, PyString, PyTuple, + }, + AsPyPointer, Bound, Py, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }, std::{ alloc::{self, Layout}, ffi::c_void, mem::{self, MaybeUninit}, + ops::DerefMut, ptr, slice, str, - sync::Once, + sync::{Mutex, Once}, }, wasi::cli::environment, }; @@ -45,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; @@ -127,9 +138,9 @@ extern "C" { #[pyo3::pyfunction] #[pyo3(pass_module)] fn call_import<'a>( - module: &'a PyModule, + module: &'a Bound, index: u32, - params: Vec<&PyAny>, + params: Vec>, result_count: usize, ) -> PyResult> { let mut results = vec![MaybeUninit::<&PyAny>::uninit(); result_count]; @@ -150,7 +161,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 +176,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 +187,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 +209,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 +263,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 +283,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 +296,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 +328,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::() + .downcast_into::() .unwrap(); let keys = environ.keys()?; @@ -338,24 +349,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::() + .downcast_into::() .unwrap(); for i in 0..argv.len() { @@ -421,22 +432,19 @@ 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<&PyAny>>(params_py); - 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().as_ref(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().as_ref(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 @@ -446,17 +454,25 @@ pub unsafe extern "C" fn componentize_py_dispatch( } let export = &EXPORTS.get().unwrap()[export]; + + // 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.as_ptr())); 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, PyTuple::new_bound(py, params_py)) } - Export::Constructor(class) => class.call1(py, PyTuple::new(py, params_py)), - Export::Method(name) => params_py[0] - .call_method1(name.as_ref(py), PyTuple::new(py, ¶ms_py[1..])) + 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, PyTuple::new_bound(py, params_py)) .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) + .and_then(|function| function.call1(py, PyTuple::new_bound(py, params_py))), }; let result = match return_style { @@ -473,8 +489,8 @@ pub unsafe extern "C" fn componentize_py_dispatch( if ERR_CONSTRUCTOR .get() .unwrap() - .as_ref(py) - .eq(result.get_type(py)) + .bind_borrowed(py) + .eq(result.get_type_bound(py)) .unwrap() { result.to_object(py) @@ -486,7 +502,6 @@ pub unsafe extern "C" fn componentize_py_dispatch( }, }; - let result = result.into_ref(py); let result_array = [result]; componentize_py_call_indirect( @@ -495,6 +510,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, + ); + } + } }); } @@ -512,38 +540,61 @@ 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 { - if value.is_true().unwrap() { +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 { 0 } } +/// # Safety +/// TODO #[export_name = "componentize-py#ToCanonI32"] -pub extern "C" fn componentize_py_to_canon_i32(_py: &Python, value: &PyAny) -> i32 { - 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 { - 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 { - 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 { - 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 = 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 } @@ -552,52 +603,56 @@ pub extern "C" fn componentize_py_to_canon_char(_py: &Python, value: &PyAny) -> /// TODO #[export_name = "componentize-py#ToCanonString"] pub unsafe extern "C" fn componentize_py_to_canon_string( - _py: &Python, + py: &Python, value: &PyAny, destination: *mut (*const u8, usize), ) { - 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, -) -> &'a PyAny { +) -> 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 - .as_ref(*py) + .bind(*py) .get_item(value.get_type()) - .unwrap() .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_ref(*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_ref(*py), + DISCRIMINANT_FIELD_INDEX => value.getattr("value").unwrap().unbind(), + PAYLOAD_FIELD_INDEX => py.None(), _ => unreachable!(), }, Type::Flags { u32_count, .. } => { @@ -611,32 +666,20 @@ pub extern "C" fn componentize_py_get_field<'a>( .nth(field) .unwrap_or(0); - unsafe { mem::transmute::(value) } - .to_object(*py) - .into_ref(*py) - .downcast() - .unwrap() + 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_ref(*py) - .downcast() - .unwrap(), - 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_ref(*py) - .downcast() - .unwrap(), + 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!(), @@ -645,7 +688,7 @@ pub extern "C" fn componentize_py_get_field<'a>( DISCRIMINANT_FIELD_INDEX => if OK_CONSTRUCTOR .get() .unwrap() - .as_ref(*py) + .bind_borrowed(*py) .eq(value.get_type()) .unwrap() { @@ -653,7 +696,7 @@ pub extern "C" fn componentize_py_get_field<'a>( } else if ERR_CONSTRUCTOR .get() .unwrap() - .as_ref(*py) + .bind_borrowed(*py) .eq(value.get_type()) .unwrap() { @@ -661,9 +704,8 @@ pub extern "C" fn componentize_py_get_field<'a>( } else { unreachable!() } - .to_object(*py) - .into_ref(*py), - PAYLOAD_FIELD_INDEX => value.getattr("value").unwrap(), + .to_object(*py), + PAYLOAD_FIELD_INDEX => value.getattr("value").unwrap().unbind(), _ => unreachable!(), }, Type::Tuple(length) => { @@ -673,13 +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 { +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 { @@ -687,85 +733,93 @@ 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, -) -> &'a PyAny { - 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<'a>, value: u32) -> &'a PyAny { - PyBool::new(*py, value != 0) +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) -> &'a PyAny { - value.to_object(*py).into_ref(*py).downcast().unwrap() +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) -> &'a PyAny { - value.to_object(*py).into_ref(*py).downcast().unwrap() +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) -> &'a PyAny { - value.to_object(*py).into_ref(*py).downcast().unwrap() +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) -> &'a PyAny { - value.to_object(*py).into_ref(*py).downcast().unwrap() +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) -> &'a PyAny { - char::from_u32(value) - .unwrap() - .to_string() - .to_object(*py) - .into_ref(*py) - .downcast() - .unwrap() +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, -) -> &'a PyAny { - PyString::new(*py, unsafe { +) -> Py { + PyString::new_bound(*py, unsafe { str::from_utf8_unchecked(slice::from_raw_parts(data, len)) }) - .as_ref() + .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, -) -> &'a PyAny { +) -> Py { match &TYPES.get().unwrap()[ty] { - Type::Record { constructor, .. } => constructor - .call1(*py, PyTuple::new(*py, slice::from_raw_parts(data, len))) - .unwrap() - .into_ref(*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() + } 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( @@ -778,14 +832,15 @@ pub unsafe extern "C" fn componentize_py_init<'a>( case.constructor.call1(*py, ()) } .unwrap() - .into_ref(*py) } 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( @@ -795,7 +850,6 @@ pub unsafe extern "C" fn componentize_py_init<'a>( )),), ) .unwrap() - .into_ref(*py) } Type::Flags { constructor, @@ -808,36 +862,45 @@ 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(), ),), ) .unwrap() - .into_ref(*py) } 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_ref(*py), - 1 => ptr::read(data.offset(isize::try_from(PAYLOAD_FIELD_INDEX).unwrap())), - + 0 => py.None(), + 1 => Py::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_ref(*py), + 0 => py.None(), 1 => SOME_CONSTRUCTOR .get() @@ -848,18 +911,19 @@ pub unsafe extern "C" fn componentize_py_init<'a>( data.offset(isize::try_from(PAYLOAD_FIELD_INDEX).unwrap()), ),), ) - .unwrap() - .into_ref(*py), + .unwrap(), _ => unreachable!(), } } 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(), @@ -873,67 +937,76 @@ pub unsafe extern "C" fn componentize_py_init<'a>( ),), ) .unwrap() - .into_ref(*py) } Type::Tuple(length) => { assert!(*length == len); - PyTuple::new(*py, slice::from_raw_parts(data, 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().unbind() } 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(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) { - list.append(element).unwrap(); +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) -> &'a PyAny { - py.None().into_ref(*py) +pub extern "C" fn componentize_py_none(py: &Python) -> Py { + py.None() } /// # Safety /// TODO #[export_name = "componentize-py#GetBytes"] pub unsafe extern "C" fn componentize_py_get_bytes( - _py: &Python, + py: &Python, src: &PyBytes, dst: *mut u8, len: usize, ) { + 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.as_bytes()) + slice::from_raw_parts_mut(dst, len) + .copy_from_slice(src.downcast::().unwrap().as_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, -) -> &'a PyAny { - PyBytes::new_with(*py, len, |dst| { +) -> 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, -) -> &'a PyAny { +) -> Py { let ty = &TYPES.get().unwrap()[usize::try_from(resource).unwrap()]; let Type::Resource { constructor, @@ -946,7 +1019,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 { Py::from_borrowed_ptr(*py, value as usize as _) } } else { let Some(LocalResource { rep, .. }) = resource_local else { panic!("expected local resource, found {ty:?}"); @@ -966,7 +1039,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 { Bound::from_borrowed_ptr(*py, rep as _) }; value .delattr(intern!(*py, "__componentize_py_handle")) @@ -978,25 +1051,32 @@ 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 { panic!("expected remote resource, found {ty:?}"); }; + if borrow != 0 { + BORROWS.lock().unwrap().push(Borrow { + handle: value, + drop: *drop, + }); + } + let instance = constructor .call_method1( *py, intern!(*py, "__new__"), - PyTuple::new(*py, [constructor]), + PyTuple::new_bound(*py, [constructor]), ) .unwrap(); 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 @@ -1005,7 +1085,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, @@ -1017,18 +1097,21 @@ pub extern "C" fn componentize_py_from_canon_handle<'a>( .setattr(*py, intern!(*py, "finalizer"), finalizer) .unwrap(); - instance.into_ref(*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 = Bound::from_borrowed_ptr(*py, value.as_ptr()); if local != 0 { let ty = &TYPES.get().unwrap()[usize::try_from(resource).unwrap()]; let Type::Resource { @@ -1068,7 +1151,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, @@ -1099,179 +1182,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 { diff --git a/src/python.rs b/src/python.rs index 00d24c6..c8504f8 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, PyModuleMethods}, + 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.as_ref()).collect::>(), + &module_worlds + .iter() + .map(|(a, b)| (a.as_ref(), b.as_ref())) + .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)?)?; 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"