Merge pull request #1133 from birkenfeld/string-apis

Avoid using CString where unnecessary
This commit is contained in:
Yuji Kanagawa 2020-09-08 17:57:26 +09:00 committed by GitHub
commit b2ba83a62f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 10 deletions

View File

@ -63,6 +63,7 @@ pub unsafe fn PyImport_ImportModuleEx(
extern "C" {
pub fn PyImport_GetImporter(path: *mut PyObject) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyImport_Import")]
pub fn PyImport_Import(name: *mut PyObject) -> *mut PyObject;
#[cfg_attr(PyPy, link_name = "PyPyImport_ReloadModule")]
pub fn PyImport_ReloadModule(m: *mut PyObject) -> *mut PyObject;

View File

@ -229,17 +229,16 @@ fn initialize_tp_dict(
tp_dict: *mut ffi::PyObject,
items: Vec<(&'static str, PyObject)>,
) -> PyResult<()> {
use std::ffi::CString;
// We hold the GIL: the dictionary update can be considered atomic from
// the POV of other threads.
for (key, val) in items {
let ret = unsafe {
ffi::PyDict_SetItemString(tp_dict, CString::new(key)?.as_ptr(), val.into_ptr())
};
if ret < 0 {
return Err(PyErr::fetch(py));
}
crate::types::with_tmp_string(py, key, |key| {
let ret = unsafe { ffi::PyDict_SetItem(tp_dict, key, val.into_ptr()) };
if ret < 0 {
return Err(PyErr::fetch(py));
}
Ok(())
})?;
}
Ok(())
}

View File

@ -21,6 +21,7 @@ pub use self::num::PyLong as PyInt;
pub use self::sequence::PySequence;
pub use self::set::{PyFrozenSet, PySet};
pub use self::slice::{PySlice, PySliceIndices};
pub(crate) use self::string::with_tmp_string;
pub use self::string::{PyString, PyString as PyUnicode};
pub use self::tuple::PyTuple;
pub use self::typeobject::PyType;

View File

@ -25,14 +25,16 @@ pyobject_native_var_type!(PyModule, ffi::PyModule_Type, ffi::PyModule_Check);
impl PyModule {
/// Creates a new module object with the `__name__` attribute set to name.
pub fn new<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> {
// Could use PyModule_NewObject, but it doesn't exist on PyPy.
let name = CString::new(name)?;
unsafe { py.from_owned_ptr_or_err(ffi::PyModule_New(name.as_ptr())) }
}
/// Imports the Python module with the specified name.
pub fn import<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> {
let name = CString::new(name)?;
unsafe { py.from_owned_ptr_or_err(ffi::PyImport_ImportModule(name.as_ptr())) }
crate::types::with_tmp_string(py, name, |name| unsafe {
py.from_owned_ptr_or_err(ffi::PyImport_Import(name))
})
}
/// Loads the Python code specified into a new module.

View File

@ -78,6 +78,24 @@ impl PyString {
}
}
/// Convenience for calling Python APIs with a temporary string
/// object created from a given Rust string.
pub(crate) fn with_tmp_string<F, R>(py: Python, s: &str, f: F) -> PyResult<R>
where
F: FnOnce(*mut ffi::PyObject) -> PyResult<R>,
{
unsafe {
let s_obj =
ffi::PyUnicode_FromStringAndSize(s.as_ptr() as *const _, s.len() as ffi::Py_ssize_t);
if s_obj.is_null() {
return Err(PyErr::fetch(py));
}
let ret = f(s_obj);
ffi::Py_DECREF(s_obj);
ret
}
}
/// Converts a Rust `str` to a Python object.
/// See `PyString::new` for details on the conversion.
impl ToPyObject for str {