python-plugin: RAII (PyOwned/PyBorrowed) + autodecode enum; crate: ny-llvmc --emit exe with NyRT link; tools: build_llvm.sh crate-exe path + crate_exe_smoke; CURRENT_TASK update
This commit is contained in:
284
plugins/nyash-python-plugin/src/ffi.rs
Normal file
284
plugins/nyash-python-plugin/src/ffi.rs
Normal file
@ -0,0 +1,284 @@
|
||||
#![allow(non_snake_case, non_camel_case_types, dead_code)]
|
||||
use libloading::Library;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::os::raw::{c_char, c_int, c_long, c_void};
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub type PyObject = c_void;
|
||||
pub type PyGILState_STATE = c_int;
|
||||
|
||||
pub struct CPython {
|
||||
pub(crate) _lib: Library,
|
||||
pub(crate) Py_Initialize: unsafe extern "C" fn(),
|
||||
pub(crate) Py_Finalize: unsafe extern "C" fn(),
|
||||
pub(crate) Py_IsInitialized: unsafe extern "C" fn() -> c_int,
|
||||
pub(crate) PyGILState_Ensure: unsafe extern "C" fn() -> PyGILState_STATE,
|
||||
pub(crate) PyGILState_Release: unsafe extern "C" fn(PyGILState_STATE),
|
||||
pub(crate) PyRun_StringFlags: unsafe extern "C" fn(
|
||||
*const c_char,
|
||||
c_int,
|
||||
*mut PyObject,
|
||||
*mut PyObject,
|
||||
*mut c_void,
|
||||
) -> *mut PyObject,
|
||||
pub(crate) PyImport_AddModule: unsafe extern "C" fn(*const c_char) -> *mut PyObject,
|
||||
pub(crate) PyModule_GetDict: unsafe extern "C" fn(*mut PyObject) -> *mut PyObject,
|
||||
pub(crate) PyImport_ImportModule: unsafe extern "C" fn(*const c_char) -> *mut PyObject,
|
||||
pub(crate) PyObject_Str: unsafe extern "C" fn(*mut PyObject) -> *mut PyObject,
|
||||
pub(crate) PyUnicode_AsUTF8: unsafe extern "C" fn(*mut PyObject) -> *const c_char,
|
||||
pub(crate) Py_DecRef: unsafe extern "C" fn(*mut PyObject),
|
||||
pub(crate) Py_IncRef: unsafe extern "C" fn(*mut PyObject),
|
||||
pub(crate) PyObject_GetAttrString:
|
||||
unsafe extern "C" fn(*mut PyObject, *const c_char) -> *mut PyObject,
|
||||
pub(crate) PyObject_CallObject:
|
||||
unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> *mut PyObject,
|
||||
pub(crate) PyObject_Call:
|
||||
unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> *mut PyObject,
|
||||
pub(crate) PyTuple_New: unsafe extern "C" fn(isize) -> *mut PyObject,
|
||||
pub(crate) PyTuple_SetItem: unsafe extern "C" fn(*mut PyObject, isize, *mut PyObject) -> c_int,
|
||||
pub(crate) PyLong_FromLongLong: unsafe extern "C" fn(i64) -> *mut PyObject,
|
||||
pub(crate) PyUnicode_FromString: unsafe extern "C" fn(*const c_char) -> *mut PyObject,
|
||||
pub(crate) PyBool_FromLong: unsafe extern "C" fn(c_long: c_long) -> *mut PyObject,
|
||||
pub(crate) PyFloat_FromDouble: unsafe extern "C" fn(f64) -> *mut PyObject,
|
||||
pub(crate) PyFloat_AsDouble: unsafe extern "C" fn(*mut PyObject) -> f64,
|
||||
pub(crate) PyLong_AsLongLong: unsafe extern "C" fn(*mut PyObject) -> i64,
|
||||
pub(crate) PyBytes_FromStringAndSize:
|
||||
unsafe extern "C" fn(*const c_char, isize) -> *mut PyObject,
|
||||
pub(crate) PyBytes_AsStringAndSize:
|
||||
unsafe extern "C" fn(*mut PyObject, *mut *mut c_char, *mut isize) -> c_int,
|
||||
pub(crate) PyDict_New: unsafe extern "C" fn() -> *mut PyObject,
|
||||
pub(crate) PyDict_SetItemString:
|
||||
unsafe extern "C" fn(*mut PyObject, *const c_char, *mut PyObject) -> c_int,
|
||||
pub(crate) PyErr_Occurred: unsafe extern "C" fn() -> *mut PyObject,
|
||||
pub(crate) PyErr_Fetch:
|
||||
unsafe extern "C" fn(*mut *mut PyObject, *mut *mut PyObject, *mut *mut PyObject),
|
||||
pub(crate) PyErr_Clear: unsafe extern "C" fn(),
|
||||
}
|
||||
|
||||
pub static CPY: Lazy<Mutex<Option<CPython>>> = Lazy::new(|| Mutex::new(None));
|
||||
|
||||
pub fn try_load_cpython() -> Result<(), ()> {
|
||||
let mut candidates: Vec<String> = vec![
|
||||
// Linux
|
||||
"libpython3.12.so".into(),
|
||||
"libpython3.12.so.1.0".into(),
|
||||
"libpython3.11.so".into(),
|
||||
"libpython3.11.so.1.0".into(),
|
||||
"libpython3.10.so".into(),
|
||||
"libpython3.10.so.1.0".into(),
|
||||
"libpython3.9.so".into(),
|
||||
"libpython3.9.so.1.0".into(),
|
||||
// macOS
|
||||
"libpython3.12.dylib".into(),
|
||||
"libpython3.11.dylib".into(),
|
||||
"libpython3.10.dylib".into(),
|
||||
"libpython3.9.dylib".into(),
|
||||
];
|
||||
if cfg!(target_os = "windows") {
|
||||
let dlls = [
|
||||
"python312.dll",
|
||||
"python311.dll",
|
||||
"python310.dll",
|
||||
"python39.dll",
|
||||
];
|
||||
for d in dlls {
|
||||
candidates.push(d.into());
|
||||
}
|
||||
if let Ok(pyhome) = std::env::var("PYTHONHOME") {
|
||||
for d in [
|
||||
"python312.dll",
|
||||
"python311.dll",
|
||||
"python310.dll",
|
||||
"python39.dll",
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
let p = std::path::Path::new(&pyhome).join(d);
|
||||
if p.exists() {
|
||||
candidates.push(p.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for name in candidates.into_iter() {
|
||||
if let Ok(lib) = unsafe { Library::new(&name) } {
|
||||
unsafe {
|
||||
let Py_Initialize = *lib
|
||||
.get::<unsafe extern "C" fn()>(b"Py_Initialize\0")
|
||||
.map_err(|_| ())?;
|
||||
let Py_Finalize = *lib
|
||||
.get::<unsafe extern "C" fn()>(b"Py_Finalize\0")
|
||||
.map_err(|_| ())?;
|
||||
let Py_IsInitialized = *lib
|
||||
.get::<unsafe extern "C" fn() -> c_int>(b"Py_IsInitialized\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyGILState_Ensure = *lib
|
||||
.get::<unsafe extern "C" fn() -> PyGILState_STATE>(b"PyGILState_Ensure\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyGILState_Release = *lib
|
||||
.get::<unsafe extern "C" fn(PyGILState_STATE)>(b"PyGILState_Release\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyRun_StringFlags = *lib
|
||||
.get::<unsafe extern "C" fn(
|
||||
*const c_char,
|
||||
c_int,
|
||||
*mut PyObject,
|
||||
*mut PyObject,
|
||||
*mut c_void,
|
||||
) -> *mut PyObject>(b"PyRun_StringFlags\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyImport_AddModule = *lib
|
||||
.get::<unsafe extern "C" fn(*const c_char) -> *mut PyObject>(
|
||||
b"PyImport_AddModule\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyModule_GetDict = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject) -> *mut PyObject>(
|
||||
b"PyModule_GetDict\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyImport_ImportModule = *lib
|
||||
.get::<unsafe extern "C" fn(*const c_char) -> *mut PyObject>(
|
||||
b"PyImport_ImportModule\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyObject_Str = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject) -> *mut PyObject>(b"PyObject_Str\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyUnicode_AsUTF8 = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject) -> *const c_char>(
|
||||
b"PyUnicode_AsUTF8\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let Py_DecRef = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject)>(b"Py_DecRef\0")
|
||||
.map_err(|_| ())?;
|
||||
let Py_IncRef = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject)>(b"Py_IncRef\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyObject_GetAttrString = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject, *const c_char) -> *mut PyObject>(
|
||||
b"PyObject_GetAttrString\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyObject_CallObject = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> *mut PyObject>(
|
||||
b"PyObject_CallObject\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyObject_Call = *lib
|
||||
.get::<unsafe extern "C" fn(
|
||||
*mut PyObject,
|
||||
*mut PyObject,
|
||||
*mut PyObject,
|
||||
) -> *mut PyObject>(b"PyObject_Call\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyTuple_New = *lib
|
||||
.get::<unsafe extern "C" fn(isize) -> *mut PyObject>(b"PyTuple_New\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyTuple_SetItem = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject, isize, *mut PyObject) -> c_int>(
|
||||
b"PyTuple_SetItem\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyLong_FromLongLong = *lib
|
||||
.get::<unsafe extern "C" fn(i64) -> *mut PyObject>(b"PyLong_FromLongLong\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyUnicode_FromString = *lib
|
||||
.get::<unsafe extern "C" fn(*const c_char) -> *mut PyObject>(
|
||||
b"PyUnicode_FromString\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyBool_FromLong = *lib
|
||||
.get::<unsafe extern "C" fn(c_long: c_long) -> *mut PyObject>(
|
||||
b"PyBool_FromLong\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyFloat_FromDouble = *lib
|
||||
.get::<unsafe extern "C" fn(f64) -> *mut PyObject>(b"PyFloat_FromDouble\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyFloat_AsDouble = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject) -> f64>(b"PyFloat_AsDouble\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyLong_AsLongLong = *lib
|
||||
.get::<unsafe extern "C" fn(*mut PyObject) -> i64>(b"PyLong_AsLongLong\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyBytes_FromStringAndSize = *lib
|
||||
.get::<unsafe extern "C" fn(*const c_char, isize) -> *mut PyObject>(
|
||||
b"PyBytes_FromStringAndSize\0",
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
let PyBytes_AsStringAndSize = *lib.get::<unsafe extern "C" fn(*mut PyObject, *mut *mut c_char, *mut isize) -> c_int>(b"PyBytes_AsStringAndSize\0").map_err(|_| ())?;
|
||||
let PyDict_New = *lib
|
||||
.get::<unsafe extern "C" fn() -> *mut PyObject>(b"PyDict_New\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyDict_SetItemString = *lib.get::<unsafe extern "C" fn(*mut PyObject, *const c_char, *mut PyObject) -> c_int>(b"PyDict_SetItemString\0").map_err(|_| ())?;
|
||||
let PyErr_Occurred = *lib
|
||||
.get::<unsafe extern "C" fn() -> *mut PyObject>(b"PyErr_Occurred\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyErr_Fetch =
|
||||
*lib.get::<unsafe extern "C" fn(
|
||||
*mut *mut PyObject,
|
||||
*mut *mut PyObject,
|
||||
*mut *mut PyObject,
|
||||
)>(b"PyErr_Fetch\0")
|
||||
.map_err(|_| ())?;
|
||||
let PyErr_Clear = *lib
|
||||
.get::<unsafe extern "C" fn()>(b"PyErr_Clear\0")
|
||||
.map_err(|_| ())?;
|
||||
|
||||
let cpy = CPython {
|
||||
_lib: lib,
|
||||
Py_Initialize,
|
||||
Py_Finalize,
|
||||
Py_IsInitialized,
|
||||
PyGILState_Ensure,
|
||||
PyGILState_Release,
|
||||
PyRun_StringFlags,
|
||||
PyImport_AddModule,
|
||||
PyModule_GetDict,
|
||||
PyImport_ImportModule,
|
||||
PyObject_Str,
|
||||
PyUnicode_AsUTF8,
|
||||
Py_DecRef,
|
||||
Py_IncRef,
|
||||
PyObject_GetAttrString,
|
||||
PyObject_CallObject,
|
||||
PyObject_Call,
|
||||
PyTuple_New,
|
||||
PyTuple_SetItem,
|
||||
PyLong_FromLongLong,
|
||||
PyUnicode_FromString,
|
||||
PyBool_FromLong,
|
||||
PyFloat_FromDouble,
|
||||
PyFloat_AsDouble,
|
||||
PyLong_AsLongLong,
|
||||
PyBytes_FromStringAndSize,
|
||||
PyBytes_AsStringAndSize,
|
||||
PyDict_New,
|
||||
PyDict_SetItemString,
|
||||
PyErr_Occurred,
|
||||
PyErr_Fetch,
|
||||
PyErr_Clear,
|
||||
};
|
||||
*CPY.lock().unwrap() = Some(cpy);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
||||
pub fn ensure_cpython() -> Result<(), ()> {
|
||||
if CPY.lock().unwrap().is_none() {
|
||||
try_load_cpython()?;
|
||||
unsafe {
|
||||
if let Some(cpy) = &*CPY.lock().unwrap() {
|
||||
if (cpy.Py_IsInitialized)() == 0 {
|
||||
(cpy.Py_Initialize)();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
19
plugins/nyash-python-plugin/src/gil.rs
Normal file
19
plugins/nyash-python-plugin/src/gil.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use crate::ffi::{CPython, PyGILState_STATE};
|
||||
|
||||
pub struct GILGuard<'a> {
|
||||
cpy: &'a CPython,
|
||||
state: PyGILState_STATE,
|
||||
}
|
||||
|
||||
impl<'a> GILGuard<'a> {
|
||||
pub fn acquire(cpy: &'a CPython) -> Self {
|
||||
let state = unsafe { (cpy.PyGILState_Ensure)() };
|
||||
GILGuard { cpy, state }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for GILGuard<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { (self.cpy.PyGILState_Release)(self.state) };
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
461
plugins/nyash-python-plugin/src/pytypes.rs
Normal file
461
plugins/nyash-python-plugin/src/pytypes.rs
Normal file
@ -0,0 +1,461 @@
|
||||
use crate::ffi::{self, CPython, PyObject};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_char;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub enum DecodedValue {
|
||||
Float(f64),
|
||||
Int(i64),
|
||||
Str(String),
|
||||
Bytes(Vec<u8>),
|
||||
}
|
||||
|
||||
pub struct PyOwned {
|
||||
ptr: NonNull<PyObject>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct PyBorrowed<'a> {
|
||||
ptr: NonNull<PyObject>,
|
||||
_marker: PhantomData<&'a PyObject>,
|
||||
}
|
||||
|
||||
impl PyOwned {
|
||||
pub unsafe fn from_new(ptr: *mut PyObject) -> Option<Self> {
|
||||
NonNull::new(ptr).map(|ptr| PyOwned { ptr })
|
||||
}
|
||||
|
||||
pub unsafe fn from_raw(ptr: *mut PyObject) -> Option<Self> {
|
||||
NonNull::new(ptr).map(|ptr| PyOwned { ptr })
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn from_borrowed(cpy: &CPython, borrowed: PyBorrowed<'_>) -> Self {
|
||||
(cpy.Py_IncRef)(borrowed.ptr.as_ptr());
|
||||
PyOwned { ptr: borrowed.ptr }
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut PyObject {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn borrow(&self) -> PyBorrowed<'_> {
|
||||
PyBorrowed {
|
||||
ptr: self.ptr,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn clone_ref(&self, cpy: &CPython) -> Self {
|
||||
unsafe {
|
||||
(cpy.Py_IncRef)(self.ptr.as_ptr());
|
||||
}
|
||||
PyOwned { ptr: self.ptr }
|
||||
}
|
||||
|
||||
pub fn into_raw(self) -> *mut PyObject {
|
||||
let ptr = self.ptr.as_ptr();
|
||||
std::mem::forget(self);
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PyOwned {
|
||||
fn drop(&mut self) {
|
||||
if let Ok(guard) = ffi::CPY.lock() {
|
||||
if let Some(cpy) = guard.as_ref() {
|
||||
unsafe {
|
||||
(cpy.Py_DecRef)(self.ptr.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for PyOwned {
|
||||
fn clone(&self) -> Self {
|
||||
let guard = ffi::CPY.lock().expect("CPython state poisoned");
|
||||
let cpy = guard.as_ref().expect("CPython not initialized");
|
||||
unsafe {
|
||||
(cpy.Py_IncRef)(self.ptr.as_ptr());
|
||||
}
|
||||
PyOwned { ptr: self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for PyOwned {}
|
||||
unsafe impl Sync for PyOwned {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<'a> PyBorrowed<'a> {
|
||||
pub unsafe fn new(ptr: *mut PyObject) -> Option<Self> {
|
||||
NonNull::new(ptr).map(|ptr| PyBorrowed {
|
||||
ptr,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *mut PyObject {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Copy for PyBorrowed<'a> {}
|
||||
|
||||
impl<'a> Clone for PyBorrowed<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn autodecode(cpy: &CPython, obj: *mut PyObject) -> Option<DecodedValue> {
|
||||
unsafe {
|
||||
let f = (cpy.PyFloat_AsDouble)(obj);
|
||||
if (cpy.PyErr_Occurred)().is_null() {
|
||||
return Some(DecodedValue::Float(f));
|
||||
}
|
||||
(cpy.PyErr_Clear)();
|
||||
|
||||
let i = (cpy.PyLong_AsLongLong)(obj);
|
||||
if (cpy.PyErr_Occurred)().is_null() {
|
||||
return Some(DecodedValue::Int(i));
|
||||
}
|
||||
(cpy.PyErr_Clear)();
|
||||
|
||||
let u = (cpy.PyUnicode_AsUTF8)(obj);
|
||||
if (cpy.PyErr_Occurred)().is_null() && !u.is_null() {
|
||||
let s = CStr::from_ptr(u).to_string_lossy().to_string();
|
||||
return Some(DecodedValue::Str(s));
|
||||
}
|
||||
(cpy.PyErr_Clear)();
|
||||
|
||||
let mut ptr: *mut c_char = std::ptr::null_mut();
|
||||
let mut sz: isize = 0;
|
||||
if (cpy.PyBytes_AsStringAndSize)(obj, &mut ptr, &mut sz) == 0 {
|
||||
let slice = std::slice::from_raw_parts(ptr as *const u8, sz as usize);
|
||||
return Some(DecodedValue::Bytes(slice.to_vec()));
|
||||
}
|
||||
if !(cpy.PyErr_Occurred)().is_null() {
|
||||
(cpy.PyErr_Clear)();
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn cstring_from_str(s: &str) -> Result<CString, ()> {
|
||||
CString::new(s).map_err(|_| ())
|
||||
}
|
||||
|
||||
pub unsafe fn cstr_to_string(ptr: *const c_char) -> Option<String> {
|
||||
if ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
Some(CStr::from_ptr(ptr).to_string_lossy().to_string())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn incref(cpy: &CPython, obj: *mut PyObject) {
|
||||
(cpy.Py_IncRef)(obj);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn decref(cpy: &CPython, obj: *mut PyObject) {
|
||||
(cpy.Py_DecRef)(obj);
|
||||
}
|
||||
|
||||
pub fn take_py_error_string(cpy: &CPython) -> Option<String> {
|
||||
unsafe {
|
||||
if (cpy.PyErr_Occurred)().is_null() {
|
||||
return None;
|
||||
}
|
||||
let mut ptype: *mut PyObject = std::ptr::null_mut();
|
||||
let mut pvalue: *mut PyObject = std::ptr::null_mut();
|
||||
let mut ptrace: *mut PyObject = std::ptr::null_mut();
|
||||
(cpy.PyErr_Fetch)(&mut ptype, &mut pvalue, &mut ptrace);
|
||||
let s = if !pvalue.is_null() {
|
||||
let sobj = (cpy.PyObject_Str)(pvalue);
|
||||
if sobj.is_null() {
|
||||
(cpy.PyErr_Clear)();
|
||||
return Some("Python error".to_string());
|
||||
}
|
||||
let cstr = (cpy.PyUnicode_AsUTF8)(sobj);
|
||||
let msg = if cstr.is_null() {
|
||||
"Python error".to_string()
|
||||
} else {
|
||||
CStr::from_ptr(cstr).to_string_lossy().to_string()
|
||||
};
|
||||
(cpy.Py_DecRef)(sobj);
|
||||
msg
|
||||
} else {
|
||||
"Python error".to_string()
|
||||
};
|
||||
(cpy.PyErr_Clear)();
|
||||
Some(s)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count_tlv_args(args: *const u8, args_len: usize) -> usize {
|
||||
if args.is_null() || args_len < 4 {
|
||||
return 0;
|
||||
}
|
||||
let buf = unsafe { std::slice::from_raw_parts(args, args_len) };
|
||||
if buf.len() < 4 {
|
||||
return 0;
|
||||
}
|
||||
u16::from_le_bytes([buf[2], buf[3]]) as usize
|
||||
}
|
||||
|
||||
pub fn tuple_from_tlv(
|
||||
cpy: &CPython,
|
||||
args: *const u8,
|
||||
args_len: usize,
|
||||
) -> Result<*mut PyObject, ()> {
|
||||
let argc = count_tlv_args(args, args_len) as isize;
|
||||
let tuple = unsafe { (cpy.PyTuple_New)(argc) };
|
||||
if tuple.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
if argc == 0 {
|
||||
return Ok(tuple);
|
||||
}
|
||||
if !fill_tuple_from_tlv(cpy, tuple, args, args_len) {
|
||||
unsafe {
|
||||
(cpy.Py_DecRef)(tuple);
|
||||
}
|
||||
return Err(());
|
||||
}
|
||||
Ok(tuple)
|
||||
}
|
||||
|
||||
pub fn kwargs_from_tlv(
|
||||
cpy: &CPython,
|
||||
args: *const u8,
|
||||
args_len: usize,
|
||||
) -> Result<*mut PyObject, ()> {
|
||||
let dict = unsafe { (cpy.PyDict_New)() };
|
||||
if dict.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
if !fill_kwargs_from_tlv(cpy, dict, args, args_len) {
|
||||
unsafe {
|
||||
(cpy.Py_DecRef)(dict);
|
||||
}
|
||||
return Err(());
|
||||
}
|
||||
Ok(dict)
|
||||
}
|
||||
|
||||
pub fn fill_tuple_from_tlv(
|
||||
cpy: &CPython,
|
||||
tuple: *mut PyObject,
|
||||
args: *const u8,
|
||||
args_len: usize,
|
||||
) -> bool {
|
||||
if args.is_null() || args_len < 4 {
|
||||
return true;
|
||||
}
|
||||
let buf = unsafe { std::slice::from_raw_parts(args, args_len) };
|
||||
let mut off = 4usize;
|
||||
let mut idx: isize = 0;
|
||||
while off + 4 <= buf.len() {
|
||||
let tag = buf[off];
|
||||
let _rsv = buf[off + 1];
|
||||
let size = u16::from_le_bytes([buf[off + 2], buf[off + 3]]) as usize;
|
||||
if off + 4 + size > buf.len() {
|
||||
return false;
|
||||
}
|
||||
let payload = &buf[off + 4..off + 4 + size];
|
||||
let mut obj: *mut PyObject = std::ptr::null_mut();
|
||||
unsafe {
|
||||
let mut owned_transfer: Option<PyOwned> = None;
|
||||
match tag {
|
||||
1 => {
|
||||
let v = if size >= 1 && payload[0] != 0 { 1 } else { 0 };
|
||||
obj = (cpy.PyBool_FromLong)(v);
|
||||
}
|
||||
2 => {
|
||||
if size != 4 {
|
||||
return false;
|
||||
}
|
||||
let mut b = [0u8; 4];
|
||||
b.copy_from_slice(payload);
|
||||
obj = (cpy.PyLong_FromLongLong)(i32::from_le_bytes(b) as i64);
|
||||
}
|
||||
3 => {
|
||||
if size != 8 {
|
||||
return false;
|
||||
}
|
||||
let mut b = [0u8; 8];
|
||||
b.copy_from_slice(payload);
|
||||
obj = (cpy.PyLong_FromLongLong)(i64::from_le_bytes(b));
|
||||
}
|
||||
5 => {
|
||||
if size != 8 {
|
||||
return false;
|
||||
}
|
||||
let mut b = [0u8; 8];
|
||||
b.copy_from_slice(payload);
|
||||
obj = (cpy.PyFloat_FromDouble)(f64::from_le_bytes(b));
|
||||
}
|
||||
6 => {
|
||||
let c = match CString::new(payload) {
|
||||
Ok(c) => c,
|
||||
Err(_) => return false,
|
||||
};
|
||||
obj = (cpy.PyUnicode_FromString)(c.as_ptr());
|
||||
}
|
||||
7 => {
|
||||
let ptr = if size > 0 {
|
||||
payload.as_ptr() as *const c_char
|
||||
} else {
|
||||
std::ptr::null()
|
||||
};
|
||||
obj = (cpy.PyBytes_FromStringAndSize)(ptr, size as isize);
|
||||
}
|
||||
8 => {
|
||||
if size != 8 {
|
||||
return false;
|
||||
}
|
||||
let mut i = [0u8; 4];
|
||||
i.copy_from_slice(&payload[4..8]);
|
||||
let inst_id = u32::from_le_bytes(i);
|
||||
let Some(handle) = super::PY_HANDLES.lock().unwrap().get(&inst_id).cloned()
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
owned_transfer = Some(handle);
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
let raw = if let Some(handle) = owned_transfer.take() {
|
||||
handle.into_raw()
|
||||
} else {
|
||||
obj
|
||||
};
|
||||
if (cpy.PyTuple_SetItem)(tuple, idx, raw) != 0 {
|
||||
if let Some(rewrap) = PyOwned::from_raw(raw) {
|
||||
drop(rewrap);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
off += 4 + size;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn fill_kwargs_from_tlv(
|
||||
cpy: &CPython,
|
||||
dict: *mut PyObject,
|
||||
args: *const u8,
|
||||
args_len: usize,
|
||||
) -> bool {
|
||||
if args.is_null() || args_len < 4 {
|
||||
return true;
|
||||
}
|
||||
let buf = unsafe { std::slice::from_raw_parts(args, args_len) };
|
||||
let mut off = 4usize;
|
||||
while off + 4 <= buf.len() {
|
||||
// key (string)
|
||||
if buf[off] != 6 {
|
||||
return false;
|
||||
}
|
||||
let key_size = u16::from_le_bytes([buf[off + 2], buf[off + 3]]) as usize;
|
||||
if off + 4 + key_size > buf.len() {
|
||||
return false;
|
||||
}
|
||||
let key_slice = &buf[off + 4..off + 4 + key_size];
|
||||
let key_c = match CString::new(key_slice) {
|
||||
Ok(c) => c,
|
||||
Err(_) => return false,
|
||||
};
|
||||
off += 4 + key_size;
|
||||
if off + 4 > buf.len() {
|
||||
return false;
|
||||
}
|
||||
let tag_v = buf[off];
|
||||
let _rsv = buf[off + 1];
|
||||
let size_v = u16::from_le_bytes([buf[off + 2], buf[off + 3]]) as usize;
|
||||
if off + 4 + size_v > buf.len() {
|
||||
return false;
|
||||
}
|
||||
let val_payload = &buf[off + 4..off + 4 + size_v];
|
||||
let obj: *mut PyObject;
|
||||
unsafe {
|
||||
match tag_v {
|
||||
1 => {
|
||||
let v = if size_v >= 1 && val_payload[0] != 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
obj = (cpy.PyBool_FromLong)(v);
|
||||
}
|
||||
2 => {
|
||||
if size_v != 4 {
|
||||
return false;
|
||||
}
|
||||
let mut b = [0u8; 4];
|
||||
b.copy_from_slice(val_payload);
|
||||
obj = (cpy.PyLong_FromLongLong)(i32::from_le_bytes(b) as i64);
|
||||
}
|
||||
3 => {
|
||||
if size_v != 8 {
|
||||
return false;
|
||||
}
|
||||
let mut b = [0u8; 8];
|
||||
b.copy_from_slice(val_payload);
|
||||
obj = (cpy.PyLong_FromLongLong)(i64::from_le_bytes(b));
|
||||
}
|
||||
5 => {
|
||||
if size_v != 8 {
|
||||
return false;
|
||||
}
|
||||
let mut b = [0u8; 8];
|
||||
b.copy_from_slice(val_payload);
|
||||
obj = (cpy.PyFloat_FromDouble)(f64::from_le_bytes(b));
|
||||
}
|
||||
6 => {
|
||||
let c = match CString::new(val_payload) {
|
||||
Ok(c) => c,
|
||||
Err(_) => return false,
|
||||
};
|
||||
obj = (cpy.PyUnicode_FromString)(c.as_ptr());
|
||||
}
|
||||
7 => {
|
||||
let ptr = if size_v > 0 {
|
||||
val_payload.as_ptr() as *const c_char
|
||||
} else {
|
||||
std::ptr::null()
|
||||
};
|
||||
obj = (cpy.PyBytes_FromStringAndSize)(ptr, size_v as isize);
|
||||
}
|
||||
8 => {
|
||||
if size_v != 8 {
|
||||
return false;
|
||||
}
|
||||
let mut i = [0u8; 4];
|
||||
i.copy_from_slice(&val_payload[4..8]);
|
||||
let inst_id = u32::from_le_bytes(i);
|
||||
let Some(handle) = super::PY_HANDLES.lock().unwrap().get(&inst_id).cloned()
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
obj = handle.into_raw();
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
let rc = (cpy.PyDict_SetItemString)(dict, key_c.as_ptr(), obj);
|
||||
(cpy.Py_DecRef)(obj);
|
||||
if rc != 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
off += 4 + size_v;
|
||||
}
|
||||
true
|
||||
}
|
||||
Reference in New Issue
Block a user