Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 27 additions & 35 deletions src/about.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use pyo3_ffi::*;
use std::ffi::CString;
use std::ptr;

use crate::types::PyObjectPtr;
use crate::py::{self, *};

static mut ABOUT_METHODS: [PyMethodDef; 1] = [PyMethodDef::zeroed()];

Expand All @@ -21,33 +21,28 @@ pub unsafe fn create_module(parent: *mut PyObject) -> i32 {
unsafe {
ABOUT_MODULE_DEF.m_methods = ptr::addr_of_mut!(ABOUT_METHODS).cast::<PyMethodDef>();

let module = PyModule_Create(std::ptr::addr_of_mut!(ABOUT_MODULE_DEF));
let module = py::module::create(std::ptr::addr_of_mut!(ABOUT_MODULE_DEF));
if module.is_null() {
return -1;
}

let version = env!("CARGO_PKG_VERSION");
let version_cstr = format!("{version}\0");
PyModule_AddStringConstant(
module,
crate::cstr!("__version__"),
version_cstr.as_ptr() as _,
);
let version_cstring = CString::new(version).unwrap();
module.add_module_string_constant(crate::cstr!("__version__"), version_cstring.as_c_str());

// VersionInfo namedtuple
let collections = PyImport_ImportModule(crate::cstr!("collections"));
let collections = py::module::import(crate::cstr!("collections"));
if collections.is_null() {
module.decref();
return -1;
}
let namedtuple = PyObject_GetAttrString(collections, crate::cstr!("namedtuple"));
let namedtuple = collections.getattr_cstr(crate::cstr!("namedtuple"));
collections.decref();
if namedtuple.is_null() {
module.decref();
return -1;
}

let vi_cls = PyObject_CallFunction(
let vi_cls = py::call::call_function!(
namedtuple,
crate::cstr!("s[ssssss]"),
crate::cstr!("VersionInfo"),
Expand Down Expand Up @@ -82,36 +77,29 @@ pub unsafe fn create_module(parent: *mut PyObject) -> i32 {
.unwrap_or(0);

let build_hash = env!("COPIUM_BUILD_HASH");
let local_str = format!("{build_hash}\0");
let local_cstring = CString::new(build_hash).unwrap();

let vi = PyObject_CallFunction(
let vi = py::call::call_function!(
vi_cls,
crate::cstr!("lllOOs"),
major,
minor,
patch,
Py_None(),
Py_None(),
local_str.as_ptr() as *const core::ffi::c_char,
py::NoneObject,
py::NoneObject,
local_cstring.as_c_str(),
);

PyModule_AddObject(module, crate::cstr!("VersionInfo"), vi_cls);
module.add_module_object(crate::cstr!("VersionInfo"), vi_cls);
if !vi.is_null() {
PyModule_AddObject(module, crate::cstr!("__version_tuple__"), vi);
module.add_module_object(crate::cstr!("__version_tuple__"), vi);
}

// __commit_id__
PyModule_AddObject(module, crate::cstr!("__commit_id__"), Py_None().newref());
module.add_module_object(crate::cstr!("__commit_id__"), py::NoneObject.newref());

// __build_hash__
PyModule_AddStringConstant(
module,
crate::cstr!("__build_hash__"),
local_str.as_ptr() as _,
);
module.add_module_string_constant(crate::cstr!("__build_hash__"), local_cstring.as_c_str());

// Author namedtuple
let author_cls = PyObject_CallFunction(
let author_cls = py::call::call_function!(
namedtuple,
crate::cstr!("s[ss]"),
crate::cstr!("Author"),
Expand All @@ -124,18 +112,22 @@ pub unsafe fn create_module(parent: *mut PyObject) -> i32 {
return -1;
}

let author = PyObject_CallFunction(
let author = py::call::call_function!(
author_cls,
crate::cstr!("ss"),
crate::cstr!("Arseny Boykov (Bobronium)"),
crate::cstr!("hi@bobronium.me"),
);
PyModule_AddObject(module, crate::cstr!("Author"), author_cls);
module.add_module_object(crate::cstr!("Author"), author_cls);

if !author.is_null() {
let authors = PyTuple_New(1);
PyTuple_SetItem(authors, 0, author);
PyModule_AddObject(module, crate::cstr!("__authors__"), authors);
let authors = py::tuple::new(1);
if authors.is_null() {
module.decref();
return -1;
}
authors.steal_item_unchecked(0, author);
module.add_module_object(crate::cstr!("__authors__"), authors);
}

crate::add_submodule(parent, crate::cstr!("__about__"), module)
Expand Down
95 changes: 44 additions & 51 deletions src/cache.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::cell::UnsafeCell;
use std::ffi::CString;
use std::ffi::{CStr, CString};
use std::mem::MaybeUninit;
use std::os::raw::{c_char, c_int};
use std::os::raw::c_int;
use std::ptr;

use pyo3_ffi::*;

use crate::types::PyObjectPtr;
use crate::py::{self, *};

// ── Slot types ─────────────────────────────────────────────

Expand Down Expand Up @@ -69,8 +67,8 @@ init_phase!(StrEntry, ObjEntry, CacheEntry);

// ── Primitives ─────────────────────────────────────────────

pub unsafe fn intern_str(s: *const c_char) -> *mut PyObject {
unsafe { PyUnicode_InternFromString(s) }
pub unsafe fn intern_str(string: &CStr) -> *mut PyObject {
unsafe { py::unicode::intern(string).cast() }
}

/// Resolve a dotted path like "decimal.Decimal" or "xml.etree.ElementTree.Element".
Expand All @@ -80,12 +78,7 @@ pub unsafe fn intern_str(s: *const c_char) -> *mut PyObject {
pub unsafe fn resolve_path(path: &str) -> *mut PyObject {
let segments: Vec<&str> = path.split('.').collect();
if segments.is_empty() {
unsafe {
PyErr_SetString(
PyExc_ValueError,
b"cache::resolve_path: empty path\0".as_ptr().cast(),
);
}
unsafe { py::err::set_string(PyExc_ValueError, crate::cstr!("cache::resolve_path: empty path")) };
return ptr::null_mut();
}

Expand All @@ -96,18 +89,18 @@ pub unsafe fn resolve_path(path: &str) -> *mut PyObject {

let mut cur: *mut PyObject;
unsafe {
let builtins = PyEval_GetBuiltins();
let builtins = py::eval::builtins();
let builtin_hit = if !builtins.is_null() {
PyDict_GetItemString(builtins, first.as_ptr())
builtins.borrow_item_cstr(first.as_c_str())
} else {
ptr::null_mut()
};

if !builtin_hit.is_null() {
cur = builtin_hit.newref();
} else {
PyErr_Clear();
cur = PyImport_ImportModule(first.as_ptr());
py::err::clear();
cur = py::module::import(first.as_c_str());
if cur.is_null() {
return ptr::null_mut();
}
Expand All @@ -126,29 +119,29 @@ pub unsafe fn resolve_path(path: &str) -> *mut PyObject {
};

unsafe {
let next = PyObject_GetAttrString(cur, seg.as_ptr());
let next = cur.getattr_cstr(seg.as_c_str());
if !next.is_null() {
cur.decref();
cur = next;
continue;
}
PyErr_Clear();
py::err::clear();

let dotted: String = segments[..=i].join(".");
if let Ok(module_path) = CString::new(dotted) {
let module = PyImport_ImportModule(module_path.as_ptr());
let module = py::module::import(module_path.as_c_str());
if !module.is_null() {
cur.decref();
cur = module;
continue;
}
}

PyErr_Clear();
py::err::clear();
let path_cstr = CString::new(path).unwrap_or_default();
PyErr_Format(
py::err::format!(
PyExc_AttributeError,
b"cache: cannot resolve '%s' in '%s'\0".as_ptr().cast(),
crate::cstr!("cache: cannot resolve '%s' in '%s'"),
seg.as_ptr(),
path_cstr.as_ptr(),
);
Expand All @@ -163,22 +156,20 @@ pub unsafe fn resolve_path(path: &str) -> *mut PyObject {
pub unsafe fn resolve_path_optional(path: &str) -> *mut PyObject {
let result = unsafe { resolve_path(path) };
if result.is_null() {
unsafe {
PyErr_Clear();
}
unsafe { py::err::clear() };
}
result
}

unsafe fn make_globals() -> *mut PyObject {
unsafe fn make_globals() -> *mut PyDictObject {
unsafe {
let globals = PyDict_New();
let globals = py::dict::new();
if globals.is_null() {
return ptr::null_mut();
}
let builtins = PyEval_GetBuiltins();
let builtins = py::eval::builtins();
if !builtins.is_null()
&& PyDict_SetItemString(globals, b"__builtins__\0".as_ptr().cast(), builtins) < 0
&& globals.set_item_cstr(crate::cstr!("__builtins__"), builtins) < 0
{
globals.decref();
return ptr::null_mut();
Expand All @@ -187,31 +178,31 @@ unsafe fn make_globals() -> *mut PyObject {
}
}

pub unsafe fn eval_cstr(code: *const c_char) -> *mut PyObject {
pub unsafe fn eval_cstr(code: &CStr) -> *mut PyObject {
unsafe {
let globals = make_globals();
if globals.is_null() {
return ptr::null_mut();
}
let result = PyRun_StringFlags(code, Py_eval_input, globals, globals, ptr::null_mut());
let result = py::eval::run_string(code, Py_eval_input, globals, globals);
globals.decref();
result
}
}

pub unsafe fn exec_cstr(code: *const c_char) -> *mut PyDictObject {
pub unsafe fn exec_cstr(code: &CStr) -> *mut PyDictObject {
unsafe {
let globals = make_globals();
if globals.is_null() {
return ptr::null_mut();
}
let result = PyRun_StringFlags(code, Py_file_input, globals, globals, ptr::null_mut());
let result = py::eval::run_string(code, Py_file_input, globals, globals);
if result.is_null() {
globals.decref();
return ptr::null_mut();
}
result.decref();
globals as *mut PyDictObject
globals
}
}

Expand All @@ -238,12 +229,12 @@ fn dedent(s: &str) -> CString {

pub unsafe fn eval_str(s: &str) -> *mut PyObject {
let code = dedent(s);
unsafe { eval_cstr(code.as_ptr()) }
unsafe { eval_cstr(code.as_c_str()) }
}

pub unsafe fn exec_str(s: &str) -> *mut PyDictObject {
let code = dedent(s);
unsafe { exec_cstr(code.as_ptr()) }
unsafe { exec_cstr(code.as_c_str()) }
}

// ── Init ───────────────────────────────────────────────────
Expand Down Expand Up @@ -273,9 +264,7 @@ macro_rules! py_str {
static SLOT: $crate::cache::PtrSlot = $crate::cache::PtrSlot::new();

unsafe fn __init() -> ::std::os::raw::c_int {
let val = $crate::cache::intern_str(
concat!($s, "\0").as_ptr() as *const ::std::os::raw::c_char
);
let val = $crate::cache::intern_str($crate::cstr!($s));
if val.is_null() {
return -1;
}
Expand Down Expand Up @@ -330,10 +319,10 @@ macro_rules! __py_obj_impl {
#[macro_export]
macro_rules! py_obj {
($path:literal) => {
$crate::__py_obj_impl!(required, *mut ::pyo3_ffi::PyObject, $path)
$crate::__py_obj_impl!(required, *mut $crate::py::PyObject, $path)
};
(? $path:literal) => {
$crate::__py_obj_impl!(optional, *mut ::pyo3_ffi::PyObject, $path)
$crate::__py_obj_impl!(optional, *mut $crate::py::PyObject, $path)
};
($T:ty, $path:literal) => {
$crate::__py_obj_impl!(required, *mut $T, $path)
Expand All @@ -354,13 +343,17 @@ macro_rules! py_type {
if val.is_null() {
return -1;
}
if ::pyo3_ffi::PyType_Check(val) == 0 {
::pyo3_ffi::PyErr_SetString(
::pyo3_ffi::PyExc_TypeError,
concat!("py_type!(\"", $path, "\"): resolved to non-type\0").as_ptr()
as *const ::std::os::raw::c_char,
if !$crate::py::PyObjectPtr::is_type(val) {
$crate::py::err::set_string(
$crate::py::PyExc_TypeError,
unsafe {
::std::ffi::CStr::from_bytes_with_nul_unchecked(
concat!("py_type!(\"", $path, "\"): resolved to non-type\0")
.as_bytes(),
)
},
);
$crate::types::PyObjectPtr::decref(val);
$crate::py::PyObjectPtr::decref(val);
return -1;
}
SLOT.set(val);
Expand All @@ -370,7 +363,7 @@ macro_rules! py_type {

::inventory::submit! { $crate::cache::ObjEntry { init_fn: __init } }

unsafe { SLOT.get() as *mut ::pyo3_ffi::PyTypeObject }
unsafe { SLOT.get() as *mut $crate::py::PyTypeObject }
}};
}

Expand All @@ -383,8 +376,8 @@ macro_rules! py_cache {

#[allow(unused_unsafe)]
unsafe fn __init() -> ::std::os::raw::c_int {
let val: *mut ::pyo3_ffi::PyObject =
(|| -> *mut ::pyo3_ffi::PyObject { unsafe { $($body)+ } })();
let val: *mut $crate::py::PyObject =
(|| -> *mut $crate::py::PyObject { unsafe { $($body)+ } })();
if val.is_null() {
return -1;
}
Expand Down
Loading
Loading