diff --git a/bro.py b/bro.py index 226a16b..f3fefaa 100644 --- a/bro.py +++ b/bro.py @@ -1,3 +1,4 @@ def hello(name): print("Hello, bro! " + name) - return "Idk, return value i guess" \ No newline at end of file + # return "Idk, return value i guess" + return 1.1 \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index fe498b9..917d612 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,13 @@ -#[derive(Debug)] +use std::collections::BTreeMap; + +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum FluxValue { Int(i64), - Float(f64), + Float(u64), Str(String), Null, - // later: List(Vec), Dict(HashMap) + Array(Vec), + Map(BTreeMap), } pub trait Serialize { @@ -21,9 +24,15 @@ pub trait FluxModule { fn call(&self, func: &str, args: Vec<&dyn Serialize>) -> FluxValue; } -pub mod values; pub mod runtime; +pub mod values; pub mod prelude { - pub use crate::{FluxModule, Serialize, Deserialize}; + pub use crate::{Deserialize, FluxModule, Serialize}; +} + +impl FluxValue { + pub fn extract(self) -> T { + T::deserialize(self) + } } diff --git a/src/main.rs b/src/main.rs index 6974ee2..230c6f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,5 +7,5 @@ fn main() { let gil = python::get_gil(); let m = python::import("bro.py", &gil); - println!("{:?}", m.call("hello", vec![&"leo"])); + println!("{:?}", m.call("hello", vec![&"leo"]).extract::()); } diff --git a/src/runtime/python.rs b/src/runtime/python.rs index eeae6b2..1d39619 100644 --- a/src/runtime/python.rs +++ b/src/runtime/python.rs @@ -1,7 +1,9 @@ use std::fs; -use crate::FluxModule; -use cpython::{GILGuard, ObjectProtocol, PyObject, PyTuple, Python, PythonObject, ToPyObject}; +use crate::{FluxModule, FluxValue}; +use cpython::{ + GILGuard, ObjectProtocol, PyDict, PyList, PyObject, PyTuple, Python, PythonObject, ToPyObject, +}; pub fn import<'a>(path: &str, gil: &'a GILGuard) -> PythonModule<'a> { let m = PythonModule { @@ -16,6 +18,30 @@ pub fn get_gil() -> GILGuard { Python::acquire_gil() } +pub fn flux_to_object(py: Python<'_>, flux: &FluxValue) -> PyObject { + match flux { + crate::FluxValue::Null => py.None(), + crate::FluxValue::Int(i) => i.to_py_object(py).into_object(), + crate::FluxValue::Float(f) => f.to_py_object(py).into_object(), + crate::FluxValue::Str(s) => s.to_py_object(py).into_object(), + crate::FluxValue::Array(a) => PyList::new( + py, + &a.iter() + .map(|f| flux_to_object(py, f)) + .collect::>(), + ) + .into_object(), + crate::FluxValue::Map(a) => { + let map = PyDict::new(py); + for (k, v) in a { + map.set_item(py, flux_to_object(py, k), flux_to_object(py, v)) + .unwrap(); + } + map.into_object() + } + } +} + pub struct PythonModule<'a> { path: String, python: Python<'a>, @@ -33,28 +59,41 @@ impl FluxModule for PythonModule<'_> { 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(), - }) + .map(|a| flux_to_object(self.python, &a.serialize())) .collect(); let args_tuple = PyTuple::new(self.python, &py_args); 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 - } + to_flux_value(self.python, &result) } fn end(&self) {} } + +fn to_flux_value(py: Python, result: &PyObject) -> crate::FluxValue { + if let Ok(i) = result.extract::(py) { + crate::FluxValue::Int(i) + } else if let Ok(f) = result.extract::(py) { + crate::FluxValue::Float(f.to_bits()) + } else if let Ok(s) = result.extract::(py) { + crate::FluxValue::Str(s) + } else if let Ok(list) = result.cast_as::(py) { + let mut items = Vec::new(); + for item in list.iter(py) { + items.push(to_flux_value(py, &item)); + } + crate::FluxValue::Array(items) + } else if let Ok(dict) = result.cast_as::(py) { + let mut map = std::collections::BTreeMap::new(); // or HashMap if you don’t need ordering + for (k, v) in dict.items(py) { + let key = to_flux_value(py, &k); + let val = to_flux_value(py, &v); + map.insert(key, val); + } + crate::FluxValue::Map(map) + } else { + crate::FluxValue::Null + } +} diff --git a/src/values.rs b/src/values.rs index 611e5b0..00b306e 100644 --- a/src/values.rs +++ b/src/values.rs @@ -1,3 +1,5 @@ +use std::collections::{BTreeMap, HashMap}; + use crate::{Deserialize, FluxValue, Serialize}; impl Serialize for i64 { @@ -5,21 +7,61 @@ impl Serialize for i64 { FluxValue::Int(*self) } } + impl Serialize for f64 { fn serialize(&self) -> FluxValue { - FluxValue::Float(*self) + FluxValue::Float(self.to_bits()) } } + +impl Deserialize for f64 { + fn deserialize(v: FluxValue) -> Self { + match v { + FluxValue::Float(bits) => f64::from_bits(bits), + v => panic!("Expected Int, instead got {v:?}"), + } + } +} + impl Serialize for &str { fn serialize(&self) -> FluxValue { FluxValue::Str(self.to_string()) } } + +impl Serialize for String { + fn serialize(&self) -> FluxValue { + FluxValue::Str(self.clone()) + } +} + impl Deserialize for i64 { fn deserialize(v: FluxValue) -> Self { match v { FluxValue::Int(i) => i, - _ => panic!("Expected Int"), + v => panic!("Expected Int, instead got {v:?}"), + } + } +} + +impl Serialize for HashMap { + fn serialize(&self) -> FluxValue { + FluxValue::Map( + self.iter() + .map(|(k, v)| (k.serialize(), v.serialize())) + .collect::>(), + ) + } +} + +impl Deserialize for BTreeMap { + fn deserialize(v: FluxValue) -> Self { + match v { + FluxValue::Map(m) => m + .iter() + .map(|(k, v)| (K::deserialize(k.clone()), V::deserialize(v.clone()))) + .collect::>(), + v => panic!("Expected Int, instead got {v:?}"), } } }