diff --git a/src/marshal.rs b/src/marshal.rs index 343b861d..5e62e6b6 100644 --- a/src/marshal.rs +++ b/src/marshal.rs @@ -2,14 +2,32 @@ //! Support for the Python `marshal` format. -use crate::ffi; +use crate::ffi_ptr_ext::FfiPtrExt; +use crate::py_result_ext::PyResultExt; use crate::types::{PyAny, PyBytes}; -use crate::{AsPyPointer, FromPyPointer, PyResult, Python}; -use std::os::raw::{c_char, c_int}; +use crate::{ffi, Bound}; +use crate::{AsPyPointer, PyResult, Python}; +use std::os::raw::c_int; /// The current version of the marshal binary format. pub const VERSION: i32 = 4; +/// Deprecated form of [`dumps_bound`] +#[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`dumps` will be replaced by `dumps_bound` in a future PyO3 version" + ) +)] +pub fn dumps<'py>( + py: Python<'py>, + object: &impl AsPyPointer, + version: i32, +) -> PyResult<&'py PyBytes> { + dumps_bound(py, object, version).map(Bound::into_gil_ref) +} + /// Serialize an object to bytes using the Python built-in marshal module. /// /// The built-in marshalling only supports a limited range of objects. @@ -27,33 +45,52 @@ pub const VERSION: i32 = 4; /// dict.set_item("mies", "wim").unwrap(); /// dict.set_item("zus", "jet").unwrap(); /// -/// let bytes = marshal::dumps(py, dict, marshal::VERSION); +/// let bytes = marshal::dumps_bound(py, dict, marshal::VERSION); /// # }); /// ``` -pub fn dumps<'a>(py: Python<'a>, object: &impl AsPyPointer, version: i32) -> PyResult<&'a PyBytes> { +pub fn dumps_bound<'py>( + py: Python<'py>, + object: &impl AsPyPointer, + version: i32, +) -> PyResult> { unsafe { - let bytes = ffi::PyMarshal_WriteObjectToString(object.as_ptr(), version as c_int); - FromPyPointer::from_owned_ptr_or_err(py, bytes) + ffi::PyMarshal_WriteObjectToString(object.as_ptr(), version as c_int) + .assume_owned_or_err(py) + .downcast_into_unchecked() } } +/// Deprecated form of [`loads_bound`] +#[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`loads` will be replaced by `loads_bound` in a future PyO3 version" + ) +)] +pub fn loads<'py, B>(py: Python<'py>, data: &B) -> PyResult<&'py PyAny> +where + B: AsRef<[u8]> + ?Sized, +{ + loads_bound(py, data).map(Bound::into_gil_ref) +} + /// Deserialize an object from bytes using the Python built-in marshal module. -pub fn loads<'a, B>(py: Python<'a>, data: &B) -> PyResult<&'a PyAny> +pub fn loads_bound<'py, B>(py: Python<'py>, data: &B) -> PyResult> where B: AsRef<[u8]> + ?Sized, { let data = data.as_ref(); unsafe { - let c_str = data.as_ptr() as *const c_char; - let object = ffi::PyMarshal_ReadObjectFromString(c_str, data.len() as isize); - FromPyPointer::from_owned_ptr_or_err(py, object) + ffi::PyMarshal_ReadObjectFromString(data.as_ptr().cast(), data.len() as isize) + .assume_owned_or_err(py) } } #[cfg(test)] mod tests { use super::*; - use crate::types::PyDict; + use crate::types::{bytes::PyBytesMethods, PyDict}; #[test] fn marshal_roundtrip() { @@ -63,12 +100,10 @@ mod tests { dict.set_item("mies", "wim").unwrap(); dict.set_item("zus", "jet").unwrap(); - let bytes = dumps(py, dict, VERSION) - .expect("marshalling failed") - .as_bytes(); - let deserialized = loads(py, bytes).expect("unmarshalling failed"); + let pybytes = dumps_bound(py, dict, VERSION).expect("marshalling failed"); + let deserialized = loads_bound(py, pybytes.as_bytes()).expect("unmarshalling failed"); - assert!(equal(py, dict, deserialized)); + assert!(equal(py, dict, &deserialized)); }); }