#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
use pyo3::exceptions::{PyValueError, PyRuntimeError};
#[cfg(feature = "python")]
use std::collections::HashMap;
#[cfg(feature = "python")]
use crate::dna::atp::value::Value as HlxValue;
#[cfg(feature = "python")]
use crate::dna::atp::interpreter::HelixInterpreter;
#[cfg(feature = "python")]
use crate::dna::ops::fundamental::{OperatorRegistry, ExecutionContext, RequestData};
#[cfg(feature = "python")]
#[pyclass]
#[derive(Clone, Debug)]
pub struct Value {
inner: HlxValue,
}
#[cfg(feature = "python")]
#[pymethods]
impl Value {
fn as_string(&self) -> PyResult<String> {
match &self.inner {
HlxValue::String(s) => Ok(s.clone()),
_ => Err(PyValueError::new_err("Value is not a string")),
}
}
fn as_number(&self) -> PyResult<f64> {
match &self.inner {
HlxValue::Number(n) => Ok(*n),
_ => Err(PyValueError::new_err("Value is not a number")),
}
}
fn as_bool(&self) -> PyResult<bool> {
match &self.inner {
HlxValue::Bool(b) => Ok(*b),
_ => Err(PyValueError::new_err("Value is not a boolean")),
}
}
fn as_dict(&self) -> PyResult<HashMap<String, PyObject>> {
match &self.inner {
HlxValue::Object(obj) => {
let mut result = HashMap::new();
for (k, v) in obj {
result.insert(k.clone(), value_to_pyobject(v)?);
}
Ok(result)
}
_ => Err(PyValueError::new_err("Value is not an object")),
}
}
fn as_list(&self) -> PyResult<Vec<PyObject>> {
match &self.inner {
HlxValue::Array(arr) => {
let mut result = Vec::new();
for v in arr {
result.push(value_to_pyobject(v)?);
}
Ok(result)
}
_ => Err(PyValueError::new_err("Value is not an array")),
}
}
fn to_python(&self, py: Python) -> PyObject {
match &self.inner {
HlxValue::String(s) => s.clone().into_py(py),
HlxValue::Number(n) => n.into_py(py),
HlxValue::Bool(b) => b.into_py(py),
HlxValue::Null => py.None(),
_ => py.None(),
}
}
}
#[cfg(feature = "python")]
fn types_value_to_pyobject(value: &crate::dna::atp::types::Value) -> PyResult<PyObject> {
Python::with_gil(|py| {
match value {
crate::dna::atp::types::Value::String(s) => Ok(s.clone().into_py(py)),
crate::dna::atp::types::Value::Number(n) => Ok(n.into_py(py)),
crate::dna::atp::types::Value::Bool(b) => Ok(b.into_py(py)),
crate::dna::atp::types::Value::Null => Ok(py.None()),
crate::dna::atp::types::Value::Array(arr) => {
let list = pyo3::types::PyList::new_bound(py, []);
for v in arr {
list.append(types_value_to_pyobject(v)?)?;
}
Ok(list.into())
}
crate::dna::atp::types::Value::Object(obj) => {
let dict = pyo3::types::PyDict::new_bound(py);
for (k, v) in obj {
dict.set_item(k, types_value_to_pyobject(v)?)?;
}
Ok(dict.into())
}
_ => Ok(py.None()),
}
})
}
#[cfg(feature = "python")]
fn value_to_pyobject(value: &HlxValue) -> PyResult<PyObject> {
Python::with_gil(|py| {
match value {
HlxValue::String(s) => Ok(s.clone().into_py(py)),
HlxValue::Number(n) => Ok(n.into_py(py)),
HlxValue::Bool(b) => Ok(b.into_py(py)),
HlxValue::Array(arr) => {
let list = pyo3::types::PyList::new_bound(py, []);
for v in arr {
list.append(value_to_pyobject(v)?)?;
}
Ok(list.into())
}
HlxValue::Object(obj) => {
let dict = pyo3::types::PyDict::new_bound(py);
for (k, v) in obj {
dict.set_item(k, value_to_pyobject(v)?)?;
}
Ok(dict.into())
}
HlxValue::Null => Ok(py.None()),
_ => Ok(py.None()),
}
})
}
#[cfg(feature = "python")]
#[pyclass]
#[derive(Clone, Debug)]
pub struct PyExecutionContext {
inner: ExecutionContext,
}
#[cfg(feature = "python")]
#[pymethods]
impl PyExecutionContext {
#[new]
fn new(
request: Option<HashMap<String, PyObject>>,
session: Option<HashMap<String, PyObject>>,
cookies: Option<HashMap<String, String>>,
headers: Option<HashMap<String, String>>,
params: Option<HashMap<String, String>>,
query: Option<HashMap<String, String>>,
) -> Self {
let mut context = ExecutionContext::default();
if let Some(req) = request {
context.request = RequestData {
method: "GET".to_string(),
url: "".to_string(),
headers: HashMap::new(),
body: "".to_string(),
};
}
if let Some(sess) = session {
context.session = sess.into_iter().map(|(k, v)| (k, HlxValue::String(format!("{:?}", v)))).collect();
}
if let Some(cook) = cookies {
context.cookies = cook;
}
if let Some(head) = headers {
context.headers = head;
}
if let Some(param) = params {
context.params = param;
}
if let Some(q) = query {
context.query = q;
}
PyExecutionContext { inner: context }
}
#[getter]
fn request(&self) -> HashMap<String, String> {
let mut result = HashMap::new();
result.insert("method".to_string(), self.inner.request.method.clone());
result.insert("url".to_string(), self.inner.request.url.clone());
result.insert("body".to_string(), self.inner.request.body.clone());
result
}
#[getter]
fn session(&self) -> HashMap<String, String> {
self.inner.session.iter().map(|(k, v)| (k.clone(), format!("{:?}", v))).collect()
}
#[getter]
fn cookies(&self) -> HashMap<String, String> {
self.inner.cookies.clone()
}
#[getter]
fn headers(&self) -> HashMap<String, String> {
self.inner.headers.clone()
}
#[getter]
fn params(&self) -> HashMap<String, String> {
self.inner.params.clone()
}
#[getter]
fn query(&self) -> HashMap<String, String> {
self.inner.query.clone()
}
}
#[cfg(feature = "python")]
#[pyclass]
pub struct PyOperatorRegistry {
inner: OperatorRegistry,
}
#[cfg(feature = "python")]
#[pymethods]
impl PyOperatorRegistry {
#[new]
fn new(context: PyExecutionContext) -> PyResult<Self> {
let _ = context; let registry = tokio::runtime::Runtime::new()
.unwrap()
.block_on(async { OperatorRegistry::new().await })
.map_err(|e| PyRuntimeError::new_err(
format!("Failed to create registry: {}", e),
))?;
Ok(PyOperatorRegistry { inner: registry })
}
fn execute(&self, operator: String, params: String) -> PyResult<Value> {
let result = tokio::runtime::Runtime::new()
.unwrap()
.block_on(async { self.inner.execute(&operator, ¶ms).await })
.map_err(|e| PyRuntimeError::new_err(
format!("Operator execution failed: {}", e),
))?;
Ok(Value { inner: result })
}
}
#[cfg(feature = "python")]
#[pyclass]
#[derive(Clone, Debug)]
pub struct PyHelixConfig {
data: HashMap<String, HlxValue>,
}
#[cfg(feature = "python")]
#[pymethods]
impl PyHelixConfig {
#[new]
fn new() -> Self {
PyHelixConfig {
data: HashMap::new(),
}
}
fn get(&self, key: String) -> Option<PyObject> {
self.data
.get(&key)
.map(|value| {
Python::with_gil(|py| {
match value {
HlxValue::String(s) => s.clone().into_py(py),
HlxValue::Number(n) => n.into_py(py),
HlxValue::Bool(b) => b.into_py(py),
HlxValue::Array(arr) => {
let list = pyo3::types::PyList::new_bound(py, []);
for v in arr {
list.append(value_to_pyobject(v).unwrap_or_else(|_| py.None()))?;
}
Ok(list.into())
}
HlxValue::Object(obj) => {
let dict = pyo3::types::PyDict::new_bound(py);
for (k, v) in obj {
dict.set_item(k, value_to_pyobject(v).unwrap_or_else(|_| py.None()))?;
}
Ok(dict.into())
}
HlxValue::Null => Ok(py.None()),
_ => Ok(py.None()),
}
})
})
.unwrap_or_else(|_| Python::with_gil(|py| py.None()))
}
fn set(&mut self, key: String, value: PyObject) -> PyResult<()> {
Python::with_gil(|py| {
let helix_value = match value.extract::<String>(py) {
Ok(s) => HlxValue::String(s),
Err(_) => match value.extract::<f64>(py) {
Ok(n) => HlxValue::Number(n),
Err(_) => match value.extract::<bool>(py) {
Ok(b) => HlxValue::Bool(b),
Err(_) => HlxValue::Null,
},
},
};
self.data.insert(key, helix_value);
Ok(())
})
}
fn items(&self) -> Vec<(String, PyObject)> {
self.data
.iter()
.map(|(k, v)| {
Python::with_gil(|py| {
let obj = match v {
HlxValue::String(s) => s.clone().into_py(py),
HlxValue::Number(n) => n.into_py(py),
HlxValue::Bool(b) => b.into_py(py),
HlxValue::Null => py.None(),
_ => py.None(),
};
(k.clone(), obj)
})
})
.collect()
}
}
#[cfg(feature = "python")]
#[pyclass]
pub struct PyHelixInterpreter {
inner: HelixInterpreter,
}
#[cfg(feature = "python")]
#[pymethods]
impl PyHelixInterpreter {
#[new]
fn new() -> PyResult<Self> {
let interpreter = tokio::runtime::Runtime::new()
.unwrap()
.block_on(async { HelixInterpreter::new().await })
.map_err(|e| PyRuntimeError::new_err(
format!("Failed to create interpreter: {}", e),
))?;
Ok(PyHelixInterpreter { inner: interpreter })
}
fn execute<'py>(&self, py: Python<'py>, expression: String) -> PyResult<PyObject> {
let rt = tokio::runtime::Runtime::new()
.map_err(|e| PyRuntimeError::new_err(
format!("Failed to create runtime: {}", e),
))?;
rt.block_on(async {
let result = self.inner
.execute_expression(&expression)
.await
.map_err(|e| PyRuntimeError::new_err(
format!("Failed to create interpreter: {}", e),
))?;
Python::with_gil(|py| {
let obj: PyObject = match result {
HlxValue::String(s) => s.clone().into_py(py),
HlxValue::Number(n) => n.into_py(py),
HlxValue::Bool(b) => b.into_py(py),
HlxValue::Null => py.None(),
_ => py.None(),
};
Ok(obj)
})
})
}
fn set_variable(&mut self, name: String, value: PyObject) -> PyResult<()> {
Python::with_gil(|py| {
let helix_value = match value.extract::<String>(py) {
Ok(s) => HlxValue::String(s),
Err(_) => match value.extract::<f64>(py) {
Ok(n) => HlxValue::Number(n),
Err(_) => match value.extract::<bool>(py) {
Ok(b) => HlxValue::Bool(b),
Err(_) => HlxValue::Null,
},
},
};
self.inner.set_variable(&name, helix_value);
Ok(())
})
}
fn get_variable(&self, name: String) -> Option<PyObject> {
if let Some(value) = self.inner.get_variable(&name) {
Python::with_gil(|py| {
let obj: PyObject = match value {
HlxValue::String(s) => s.clone().into_py(py),
HlxValue::Number(n) => n.into_py(py),
HlxValue::Bool(b) => b.into_py(py),
HlxValue::Null => py.None(),
_ => py.None(),
};
Some(obj)
})
} else {
None
}
}
}
#[cfg(feature = "python")]
#[pyfunction]
fn parse(source: String) -> PyResult<PyHelixConfig> {
let config_result = crate::parse_and_validate(&source)
.map_err(|e| PyValueError::new_err(format!("Parse error: {}", e)))?;
let mut py_config = PyHelixConfig::new();
if let Ok(config_json) = serde_json::to_string(&config_result) {
if let Ok(value) = serde_json::from_str::<serde_json::Value>(&config_json) {
if let Some(obj) = value.as_object() {
for (k, v) in obj {
let helix_value = match v {
serde_json::Value::String(s) => HlxValue::String(s.clone()),
serde_json::Value::Number(n) => HlxValue::Number(n.as_f64().unwrap_or(0.0)),
serde_json::Value::Bool(b) => HlxValue::Bool(*b),
serde_json::Value::Null => HlxValue::Null,
serde_json::Value::Array(arr) => {
let mut vec = Vec::new();
for item in arr {
vec.push(match item {
serde_json::Value::String(s) => HlxValue::String(s.clone()),
serde_json::Value::Number(n) => HlxValue::Number(n.as_f64().unwrap_or(0.0)),
serde_json::Value::Bool(b) => HlxValue::Bool(*b),
serde_json::Value::Null => HlxValue::Null,
_ => HlxValue::Null,
});
}
HlxValue::Array(vec)
}
serde_json::Value::Object(obj) => {
let mut map = HashMap::new();
for (key, val) in obj {
map.insert(key.clone(), match val {
serde_json::Value::String(s) => HlxValue::String(s.clone()),
serde_json::Value::Number(n) => HlxValue::Number(n.as_f64().unwrap_or(0.0)),
serde_json::Value::Bool(b) => HlxValue::Bool(*b),
serde_json::Value::Null => HlxValue::Null,
_ => HlxValue::Null,
});
}
HlxValue::Object(map)
}
};
py_config.data.insert(k.clone(), helix_value);
}
}
}
}
Ok(py_config)
}
#[cfg(feature = "python")]
#[pyfunction]
fn execute(
expression: String,
context: Option<HashMap<String, PyObject>>,
) -> PyResult<PyObject> {
let rt = tokio::runtime::Runtime::new()
.map_err(|e| PyRuntimeError::new_err(
format!("Failed to create runtime: {}", e),
))?;
rt.block_on(async {
let mut interpreter = HelixInterpreter::new()
.await
.map_err(|e| PyRuntimeError::new_err(
format!("Failed to create interpreter: {}", e),
))?;
if let Some(ctx) = context {
for (key, value) in ctx {
Python::with_gil(|py| {
let helix_value = match value.extract::<String>(py) {
Ok(s) => HlxValue::String(s),
Err(_) => match value.extract::<f64>(py) {
Ok(n) => HlxValue::Number(n),
Err(_) => match value.extract::<bool>(py) {
Ok(b) => HlxValue::Bool(b),
Err(_) => HlxValue::Null,
},
},
};
interpreter.set_variable(&key, helix_value);
});
}
}
let result = interpreter
.execute_expression(&expression)
.await
.map_err(|e| PyRuntimeError::new_err(
format!("Execution failed: {}", e),
))?;
Python::with_gil(|py| {
let obj: PyObject = match result {
HlxValue::String(s) => s.clone().into_py(py),
HlxValue::Number(n) => n.into_py(py),
HlxValue::Bool(b) => b.into_py(py),
HlxValue::Null => py.None(),
_ => py.None(),
};
Ok(obj)
})
})
}
#[cfg(feature = "python")]
#[pyfunction]
fn load_file(file_path: String) -> PyResult<PyHelixConfig> {
let config_result = crate::load_file(&file_path)
.map_err(|e| PyValueError::new_err(format!("File load error: {}", e)))?;
let mut py_config = PyHelixConfig::new();
if let Ok(config_json) = serde_json::to_string(&config_result) {
if let Ok(value) = serde_json::from_str::<serde_json::Value>(&config_json) {
if let Some(obj) = value.as_object() {
for (k, v) in obj {
let helix_value = match v {
serde_json::Value::String(s) => HlxValue::String(s.clone()),
serde_json::Value::Number(n) => HlxValue::Number(n.as_f64().unwrap_or(0.0)),
serde_json::Value::Bool(b) => HlxValue::Bool(*b),
serde_json::Value::Null => HlxValue::Null,
serde_json::Value::Array(arr) => {
let mut vec = Vec::new();
for item in arr {
vec.push(match item {
serde_json::Value::String(s) => HlxValue::String(s.clone()),
serde_json::Value::Number(n) => HlxValue::Number(n.as_f64().unwrap_or(0.0)),
serde_json::Value::Bool(b) => HlxValue::Bool(*b),
serde_json::Value::Null => HlxValue::Null,
_ => HlxValue::Null,
});
}
HlxValue::Array(vec)
}
serde_json::Value::Object(obj) => {
let mut map = HashMap::new();
for (key, val) in obj {
map.insert(key.clone(), match val {
serde_json::Value::String(s) => HlxValue::String(s.clone()),
serde_json::Value::Number(n) => HlxValue::Number(n.as_f64().unwrap_or(0.0)),
serde_json::Value::Bool(b) => HlxValue::Bool(*b),
serde_json::Value::Null => HlxValue::Null,
_ => HlxValue::Null,
});
}
HlxValue::Object(map)
}
};
py_config.data.insert(k.clone(), helix_value);
}
}
}
}
Ok(py_config)
}
#[cfg(feature = "python")]
#[pymodule]
fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<Value>()?;
m.add_class::<PyExecutionContext>()?;
m.add_class::<PyOperatorRegistry>()?;
m.add_class::<PyHelixConfig>()?;
m.add_class::<PyHelixInterpreter>()?;
m.add_function(wrap_pyfunction_bound!(parse, m)?)?;
m.add_function(wrap_pyfunction_bound!(execute, m)?)?;
m.add_function(wrap_pyfunction_bound!(load_file, m)?)?;
Ok(())
}