Working python interface
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
def hello():
|
def hello(name: str) -> str:
|
||||||
print("Hello, bro!")
|
print("Hello, bro! " + name)
|
||||||
|
return "Idk, return value i guess"
|
||||||
hello()
|
|
||||||
+24
-16
@@ -1,21 +1,29 @@
|
|||||||
use std::{ffi::CString, fs, path::Path};
|
pub enum FluxValue {
|
||||||
|
Int(i64),
|
||||||
#[link(name = "python3.13")]
|
Float(f64),
|
||||||
extern "C" {
|
Str(String),
|
||||||
fn Py_Initialize();
|
Null,
|
||||||
fn PyRun_SimpleString(command: *const i8) -> i32;
|
// later: List(Vec<FluxValue>), Dict(HashMap<String, FluxValue>)
|
||||||
fn Py_Finalize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_py(path: &Path) {
|
pub trait Serialize {
|
||||||
let code = fs::read_to_string(path).expect("Failed to read python script");
|
fn serialize(&self) -> FluxValue;
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
pub trait Deserialize {
|
||||||
Py_Initialize();
|
fn deserialize(v: FluxValue) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
let code = CString::new(code.as_str()).unwrap();
|
pub trait FluxModule {
|
||||||
PyRun_SimpleString(code.as_ptr());
|
fn init(&self);
|
||||||
|
fn end(&self);
|
||||||
|
fn call(&self, func: &str, args: Vec<&dyn Serialize>) -> FluxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod values;
|
||||||
|
pub mod runtime;
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use crate::{FluxModule, Serialize, Deserialize};
|
||||||
|
}
|
||||||
|
|
||||||
Py_Finalize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+5
-3
@@ -1,6 +1,8 @@
|
|||||||
use std::path::Path;
|
use flux_rt::{runtime::python::PythonModule, prelude::*};
|
||||||
use flux_rt::run_py;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
run_py(Path::new("bro.py"));
|
let bro = PythonModule("bro.py".to_string());
|
||||||
|
bro.init();
|
||||||
|
|
||||||
|
bro.call("hello", vec![]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod python;
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
use std::{ffi::{CString, c_char}, fs};
|
||||||
|
|
||||||
|
use crate::{FluxModule, FluxValue, Serialize};
|
||||||
|
|
||||||
|
#[link(name = "python3.13")]
|
||||||
|
extern "C" {
|
||||||
|
fn Py_Initialize();
|
||||||
|
fn Py_Finalize();
|
||||||
|
|
||||||
|
fn PyRun_SimpleString(command: *const i8) -> i32;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PyObject;
|
||||||
|
|
||||||
|
pub struct PythonModule(pub String);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
Py_Initialize();
|
||||||
|
PyRun_SimpleString(code.as_ptr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<FluxValue> = 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
use crate::{Deserialize, FluxValue, Serialize};
|
||||||
|
|
||||||
|
impl Serialize for i64 {
|
||||||
|
fn serialize(&self) -> FluxValue {
|
||||||
|
FluxValue::Int(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Serialize for f64 {
|
||||||
|
fn serialize(&self) -> FluxValue {
|
||||||
|
FluxValue::Float(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Serialize for &str {
|
||||||
|
fn serialize(&self) -> FluxValue {
|
||||||
|
FluxValue::Str(self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Deserialize for i64 {
|
||||||
|
fn deserialize(v: FluxValue) -> Self {
|
||||||
|
match v {
|
||||||
|
FluxValue::Int(i) => i,
|
||||||
|
_ => panic!("Expected Int"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user