From e940987abbd2ef8946735ba7a07c3fbb701d1091 Mon Sep 17 00:00:00 2001 From: Kleo Dev Date: Mon, 25 Aug 2025 02:28:25 +0200 Subject: [PATCH] Working python arg and return --- Cargo.lock | 96 +++++++++++++++++++++++++++ Cargo.toml | 4 +- bro.py | 2 +- build.rs | 13 ---- src/main.rs | 11 ++-- src/runtime/python.rs | 149 ++++++++++++++---------------------------- 6 files changed, 154 insertions(+), 121 deletions(-) delete mode 100644 build.rs diff --git a/Cargo.lock b/Cargo.lock index a7d488a..ddcbd46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,102 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "cpython" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b398a2c65baaf5892f10bb69b52508bf7a993380cc4ecd3785aaebb5c79389" +dependencies = [ + "libc", + "num-traits", + "paste", + "python3-sys", +] + [[package]] name = "flux-rt" version = "0.1.0" +dependencies = [ + "cpython", +] + +[[package]] +name = "libc" +version = "0.2.175" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "python3-sys" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f53ef6740367a09718d2cd21ba15b0d7972342a38e554736bcee7773e45c9f5" +dependencies = [ + "libc", + "regex", +] + +[[package]] +name = "regex" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" diff --git a/Cargo.toml b/Cargo.toml index bc7473a..c1e0d16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,6 @@ name = "flux-rt" version = "0.1.0" edition = "2021" -build = "build.rs" -[dependencies] \ No newline at end of file +[dependencies] +cpython = "0.7.2" diff --git a/bro.py b/bro.py index 55a1275..226a16b 100644 --- a/bro.py +++ b/bro.py @@ -1,3 +1,3 @@ -def hello(name: str) -> str: +def hello(name): print("Hello, bro! " + name) return "Idk, return value i guess" \ No newline at end of file diff --git a/build.rs b/build.rs deleted file mode 100644 index 53e850b..0000000 --- a/build.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn main() { - let lib_dir = std::process::Command::new("python3") - .arg("-c") - .arg("import sysconfig; print(sysconfig.get_config_var('LIBDIR'))") - .output() - .expect("failed to run python3") - .stdout; - - let lib_dir = String::from_utf8(lib_dir).unwrap(); - println!("cargo:rustc-link-search=native={}", lib_dir.trim()); - - println!("cargo:rustc-link-lib=python3.13"); -} diff --git a/src/main.rs b/src/main.rs index d36eac0..6974ee2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,11 @@ -use flux_rt::{runtime::python::PythonModule, prelude::*}; +use flux_rt::{ + runtime::python::{self}, + FluxModule, +}; fn main() { - let bro = PythonModule("bro.py".to_string()); - bro.init(); + let gil = python::get_gil(); + let m = python::import("bro.py", &gil); - println!("{:?}", bro.call("hello", vec![])); + println!("{:?}", m.call("hello", vec![&"leo"])); } diff --git a/src/runtime/python.rs b/src/runtime/python.rs index 17c548a..eeae6b2 100644 --- a/src/runtime/python.rs +++ b/src/runtime/python.rs @@ -1,113 +1,60 @@ -use std::{ffi::{CString, c_char}, fs}; +use std::fs; - use crate::{FluxModule, FluxValue, Serialize}; +use crate::FluxModule; +use cpython::{GILGuard, ObjectProtocol, PyObject, PyTuple, Python, PythonObject, ToPyObject}; - #[link(name = "python3.13")] - extern "C" { - fn Py_Initialize(); - fn Py_Finalize(); +pub fn import<'a>(path: &str, gil: &'a GILGuard) -> PythonModule<'a> { + let m = PythonModule { + path: path.to_string(), + python: gil.python(), + }; + m.init(); + m +} - fn PyRun_SimpleString(command: *const i8) -> i32; +pub fn get_gil() -> GILGuard { + Python::acquire_gil() +} - fn PyImport_AddModule(name: *const c_char) -> *mut PyObject; - fn PyModule_GetDict(module: *mut PyObject) -> *mut PyObject; - fn PyDict_GetItemString(dict: *mut PyObject, key: *const c_char) -> *mut PyObject; +pub struct PythonModule<'a> { + path: String, + python: Python<'a>, +} - fn PyObject_CallObject(callable: *mut PyObject, args: *mut PyObject) -> *mut PyObject; - fn Py_BuildValue(format: *const c_char, ...) -> *mut PyObject; - - fn PyLong_AsLong(obj: *mut PyObject) -> i64; +impl FluxModule for PythonModule<'_> { + fn init(&self) { + let code = fs::read_to_string(&self.path).unwrap(); + self.python.run(&code, None, None).unwrap(); } - #[repr(C)] - pub struct PyObject; + fn call(&self, func: &str, args: Vec<&dyn crate::Serialize>) -> crate::FluxValue { + let module = self.python.import("__main__").unwrap(); + let func = module.get(self.python, func).unwrap(); - pub struct PythonModule(pub String); + let py_args: Vec = args + .iter() + .map(|a| match a.serialize() { + crate::FluxValue::Int(i) => i.to_py_object(self.python).into_object(), + crate::FluxValue::Float(f) => f.to_py_object(self.python).into_object(), + crate::FluxValue::Str(s) => s.to_py_object(self.python).into_object(), + crate::FluxValue::Null => self.python.None(), + }) + .collect(); - impl FluxModule for PythonModule { - fn init(&self) { - let code = fs::read_to_string(&self.0).expect("Failed to read python script"); - let code = CString::new(code.as_str()).unwrap(); + let args_tuple = PyTuple::new(self.python, &py_args); - unsafe { - Py_Initialize(); - PyRun_SimpleString(code.as_ptr()); - } + let result: PyObject = func.call(self.python, args_tuple, None).unwrap(); + + if let Ok(i) = result.extract::(self.python) { + crate::FluxValue::Int(i) + } else if let Ok(f) = result.extract::(self.python) { + crate::FluxValue::Float(f) + } else if let Ok(s) = result.extract::(self.python) { + crate::FluxValue::Str(s) + } else { + crate::FluxValue::Null } + } - fn call(&self, func: &str, args: Vec<&dyn Serialize>) -> FluxValue { - use std::ffi::CString; - - unsafe { - // 1. Get __main__ module dict - let main_str = CString::new("__main__").unwrap(); - let module = PyImport_AddModule(main_str.as_ptr()); - let dict = PyModule_GetDict(module); - - // 2. Get function by name - let func_name = CString::new(func).unwrap(); - let func_obj = PyDict_GetItemString(dict, func_name.as_ptr()); - - if func_obj.is_null() { - panic!("Python function '{}' not found", func); - } - - let mut fmt = String::from("("); - let values: Vec = args.iter().map(|a| a.serialize()).collect(); - - for v in &values { - match v { - FluxValue::Int(_) => fmt.push('l'), // long - FluxValue::Float(_) => fmt.push('d'), // double - FluxValue::Str(_) => fmt.push('s'), // string - FluxValue::Null => fmt.push('O'), // PyObject* - } - } - fmt.push(')'); - - let fmt_c = CString::new(fmt).unwrap(); - - // Call Py_BuildValue with the right arguments - let args_obj: *mut PyObject = match values.as_slice() { - [FluxValue::Int(a), FluxValue::Int(b)] => { - Py_BuildValue(fmt_c.as_ptr(), *a, *b) - } - [FluxValue::Float(a), FluxValue::Float(b)] => { - Py_BuildValue(fmt_c.as_ptr(), *a, *b) - } - [FluxValue::Str(a), FluxValue::Str(b)] => { - let a_c = CString::new(a.as_str()).unwrap(); - let b_c = CString::new(b.as_str()).unwrap(); - Py_BuildValue(fmt_c.as_ptr(), a_c.as_ptr(), b_c.as_ptr()) - } - [FluxValue::Int(a)] => { - Py_BuildValue(fmt_c.as_ptr(), *a) - } - [FluxValue::Float(a)] => { - Py_BuildValue(fmt_c.as_ptr(), *a) - } - [FluxValue::Str(a)] => { - let a_c = CString::new(a.as_str()).unwrap(); - Py_BuildValue(fmt_c.as_ptr(), a_c.as_ptr()) - } - _ => std::ptr::null_mut(), - }; - - let result_obj = PyObject_CallObject(func_obj, args_obj); - - if result_obj.is_null() { - FluxValue::Null - } else { - let value = PyLong_AsLong(result_obj); - FluxValue::Int(value) - } - } - } - - - fn end(&self) { - unsafe { - Py_Finalize(); - } - } - } \ No newline at end of file + fn end(&self) {} +}