1use pyo3::prelude::*;
2use pyo3::exceptions::{PyValueError, PyRuntimeError};
3use std::collections::HashMap;
4use crate::dna::atp::value::Value as HlxValue;
5use crate::dna::atp::interpreter::HelixInterpreter;
6use crate::dna::ops::fundamental::{OperatorRegistry, ExecutionContext, RequestData};
7#[pyclass]
8#[derive(Clone, Debug)]
9pub struct Value {
10 inner: HlxValue,
11}
12#[pymethods]
13impl Value {
14 fn as_string(&self) -> PyResult<String> {
15 match &self.inner {
16 HlxValue::String(s) => Ok(s.clone()),
17 _ => Err(PyValueError::new_err("Value is not a string")),
18 }
19 }
20 fn as_number(&self) -> PyResult<f64> {
21 match &self.inner {
22 HlxValue::Number(n) => Ok(*n),
23 _ => Err(PyValueError::new_err("Value is not a number")),
24 }
25 }
26 fn as_bool(&self) -> PyResult<bool> {
27 match &self.inner {
28 HlxValue::Bool(b) => Ok(*b),
29 _ => Err(PyValueError::new_err("Value is not a boolean")),
30 }
31 }
32 fn as_dict(&self) -> PyResult<HashMap<String, PyObject>> {
33 match &self.inner {
34 HlxValue::Object(obj) => {
35 let mut result = HashMap::new();
36 for (k, v) in obj {
37 result.insert(k.clone(), value_to_pyobject(v)?);
38 }
39 Ok(result)
40 }
41 _ => Err(PyValueError::new_err("Value is not an object")),
42 }
43 }
44 fn as_list(&self) -> PyResult<Vec<PyObject>> {
45 match &self.inner {
46 HlxValue::Array(arr) => {
47 let mut result = Vec::new();
48 for v in arr {
49 result.push(value_to_pyobject(v)?);
50 }
51 Ok(result)
52 }
53 _ => Err(PyValueError::new_err("Value is not an array")),
54 }
55 }
56 fn is_null(&self) -> bool {
57 matches!(& self.inner, HlxValue::Null)
58 }
59 fn to_python(&self, py: Python) -> PyObject {
60 value_to_pyobject(&self.inner).unwrap_or_else(|_| py.None())
61 }
62 fn __str__(&self) -> String {
63 format!("{:?}", self.inner)
64 }
65 fn __repr__(&self) -> String {
66 format!("Value({:?})", self.inner)
67 }
68}
69fn types_value_to_pyobject(value: &crate::dna::atp::types::Value) -> PyResult<PyObject> {
70 Python::with_gil(|py| {
71 match value {
72 crate::dna::atp::types::Value::String(s) => Ok(s.clone().into_py(py)),
73 crate::dna::atp::types::Value::Number(n) => Ok(n.into_py(py)),
74 crate::dna::atp::types::Value::Bool(b) => Ok(b.into_py(py)),
75 crate::dna::atp::types::Value::Array(arr) => {
76 let mut result = Vec::new();
77 for v in arr {
78 result.push(types_value_to_pyobject(v)?);
79 }
80 Ok(result.into_py(py))
81 }
82 crate::dna::atp::types::Value::Object(obj) => {
83 let dict = pyo3::types::PyDict::new_bound(py);
84 for (k, v) in obj {
85 dict.set_item(k, types_value_to_pyobject(v)?)?;
86 }
87 Ok(dict.unbind().into())
88 }
89 crate::dna::atp::types::Value::Null => Ok(py.None()),
90 _ => Ok(py.None()),
91 }
92 })
93}
94fn value_to_pyobject(value: &HlxValue) -> PyResult<PyObject> {
95 Python::with_gil(|py| {
96 match value {
97 HlxValue::String(s) => Ok(s.clone().into_py(py)),
98 HlxValue::Number(n) => Ok(n.into_py(py)),
99 HlxValue::Bool(b) => Ok(b.into_py(py)),
100 HlxValue::Array(arr) => {
101 let mut result = Vec::new();
102 for v in arr {
103 result.push(value_to_pyobject(v)?);
104 }
105 Ok(result.into_py(py))
106 }
107 HlxValue::Object(obj) => {
108 let dict = pyo3::types::PyDict::new_bound(py);
109 for (k, v) in obj {
110 dict.set_item(k, value_to_pyobject(v)?)?;
111 }
112 Ok(dict.unbind().into())
113 }
114 HlxValue::Null => Ok(py.None()),
115 _ => Ok(py.None()),
116 }
117 })
118}
119#[pyclass]
120#[derive(Clone, Debug)]
121pub struct PyExecutionContext {
122 inner: ExecutionContext,
123}
124#[pymethods]
125impl PyExecutionContext {
126 #[new]
127 fn new(
128 request: Option<HashMap<String, PyObject>>,
129 session: Option<HashMap<String, PyObject>>,
130 cookies: Option<HashMap<String, String>>,
131 params: Option<HashMap<String, String>>,
132 query: Option<HashMap<String, String>>,
133 ) -> Self {
134 let mut context = ExecutionContext::default();
135 if let Some(req) = request {
136 let mut request_data = HashMap::new();
137 for (k, v) in req {
138 request_data.insert(k, format!("{:?}", v));
139 }
140 context.request = Some(RequestData {
141 method: "GET".to_string(),
142 url: "".to_string(),
143 headers: HashMap::new(),
144 body: "".to_string(),
145 });
146 }
147 if let Some(session) = session {
148 for (k, v) in session {
150 let _ = (k, v);
152 }
153 }
154 if let Some(cookies) = cookies {
155 context.cookies = cookies.clone();
156 }
157 if let Some(params) = params {
158 context.params = params.clone();
159 }
160 if let Some(query) = query {
161 context.query = query.clone();
162 }
163 PyExecutionContext {
164 inner: context,
165 }
166 }
167 #[getter]
168 fn request(&self) -> Option<HashMap<String, String>> {
169 self.inner
170 .request
171 .as_ref()
172 .map(|req| {
173 let mut result = HashMap::new();
174 result.insert("method".to_string(), req.method.clone());
175 result.insert("url".to_string(), req.url.clone());
176 result
177 })
178 }
179 #[getter]
180 fn session(&self) -> HashMap<String, String> {
181 HashMap::new()
182 }
183 #[getter]
184 fn cookies(&self) -> HashMap<String, String> {
185 self.inner.cookies.clone()
186 }
187 #[getter]
188 fn params(&self) -> HashMap<String, String> {
189 self.inner.params.clone()
190 }
191 #[getter]
192 fn query(&self) -> HashMap<String, String> {
193 self.inner.query.clone()
194 }
195}
196#[pyclass]
197pub struct PyOperatorRegistry {
198 inner: OperatorRegistry,
199}
200#[pymethods]
201impl PyOperatorRegistry {
202 #[new]
203 fn new(context: PyExecutionContext) -> PyResult<Self> {
204 let _ = context; let registry = tokio::runtime::Runtime::new()
206 .unwrap()
207 .block_on(async { OperatorRegistry::new().await })
208 .map_err(|e| PyRuntimeError::new_err(
209 format!("Failed to create registry: {}", e),
210 ))?;
211 Ok(PyOperatorRegistry {
212 inner: registry,
213 })
214 }
215 fn execute(&self, operator: String, params: String) -> PyResult<Value> {
216 let result = tokio::runtime::Runtime::new()
217 .unwrap()
218 .block_on(async { self.inner.execute(&operator, ¶ms).await })
219 .map_err(|e| PyRuntimeError::new_err(
220 format!("Operator execution failed: {}", e),
221 ))?;
222 Ok(Value { inner: result })
223 }
224 fn context(&self) -> PyExecutionContext {
225 use std::sync::Arc;
226 let context = Arc::clone(&self.inner.context());
227 PyExecutionContext {
228 inner: (*context).clone(),
229 }
230 }
231}
232#[pyclass]
233#[derive(Clone, Debug)]
234pub struct PyHelixConfig {
235 data: HashMap<String, HlxValue>,
236}
237#[pymethods]
238impl PyHelixConfig {
239 #[new]
240 fn new() -> Self {
241 PyHelixConfig {
242 data: HashMap::new(),
243 }
244 }
245 fn get(&self, key: String) -> Option<PyObject> {
246 self.data
247 .get(&key)
248 .map(|value| {
249 Python::with_gil(|py| {
250 match value {
251 HlxValue::String(s) => s.clone().into_py(py),
252 HlxValue::Number(n) => n.into_py(py),
253 HlxValue::Bool(b) => b.into_py(py),
254 HlxValue::Array(_) => format!("{:?}", value).into_py(py),
255 HlxValue::Object(_) => format!("{:?}", value).into_py(py),
256 HlxValue::Null => py.None(),
257 HlxValue::Duration(d) => format!("{:?}", d).into_py(py),
258 HlxValue::Reference(s) => s.clone().into_py(py),
259 HlxValue::Identifier(s) => s.clone().into_py(py),
260 }
261 })
262 })
263 }
264 fn set(&mut self, key: String, value: PyObject) -> PyResult<()> {
265 Python::with_gil(|py| {
266 let helix_value = if value.bind(py).is_none() {
267 HlxValue::Null
268 } else if let Ok(s) = value.extract::<String>(py) {
269 HlxValue::String(s)
270 } else if let Ok(n) = value.extract::<f64>(py) {
271 HlxValue::Number(n)
272 } else if let Ok(b) = value.extract::<bool>(py) {
273 HlxValue::Bool(b)
274 } else {
275 HlxValue::String(format!("{:?}", value))
276 };
277 self.data.insert(key, helix_value);
278 Ok(())
279 })
280 }
281 fn keys(&self) -> Vec<String> {
282 self.data.keys().cloned().collect()
283 }
284 fn items(&self) -> Vec<(String, PyObject)> {
285 self.data
286 .iter()
287 .map(|(k, v)| {
288 (
289 k.clone(),
290 Python::with_gil(|py| {
291 value_to_pyobject(v).unwrap_or_else(|_| py.None())
292 }),
293 )
294 })
295 .collect()
296 }
297}
298#[pyclass]
299pub struct PyHelixInterpreter {
300 inner: HelixInterpreter,
301}
302#[pymethods]
303impl PyHelixInterpreter {
304 #[new]
305 fn new() -> PyResult<Self> {
306 let interpreter = tokio::runtime::Runtime::new()
307 .unwrap()
308 .block_on(async { HelixInterpreter::new().await })
309 .map_err(|e| PyRuntimeError::new_err(
310 format!("Failed to create interpreter: {}", e),
311 ))?;
312 Ok(PyHelixInterpreter {
313 inner: interpreter,
314 })
315 }
316 fn execute<'py>(&self, py: Python<'py>, expression: String) -> PyResult<PyObject> {
317 let rt = tokio::runtime::Runtime::new()
318 .map_err(|e| PyRuntimeError::new_err(
319 format!("Failed to create runtime: {}", e),
320 ))?;
321 rt.block_on(async {
322 let mut interpreter = HelixInterpreter::new()
323 .await
324 .map_err(|e| PyRuntimeError::new_err(
325 format!("Failed to create interpreter: {}", e),
326 ))?;
327 if let Some(value) = interpreter.get_variable(&expression) {
328 value_to_pyobject(value)
329 } else {
330 Ok(format!("Executed: {}", expression).into_py(py))
331 }
332 })
333 }
334 fn set_variable(&mut self, name: String, value: PyObject) -> PyResult<()> {
335 Python::with_gil(|py| {
336 let helix_value = match value.extract::<String>(py) {
337 Ok(s) => HlxValue::String(s),
338 Err(_) => match value.extract::<f64>(py) {
339 Ok(n) => HlxValue::Number(n),
340 Err(_) => match value.extract::<bool>(py) {
341 Ok(b) => HlxValue::Bool(b),
342 Err(_) => HlxValue::String(format!("{:?}", value.bind(py))),
343 },
344 },
345 };
346 self.inner.set_variable(name, helix_value);
347 Ok(())
348 })
349 }
350 fn get_variable(&self, name: String) -> Option<PyObject> {
351 if let Some(value) = self.inner.get_variable(&name) {
352 Python::with_gil(|py| {
353 let obj: PyObject = match value {
354 HlxValue::String(s) => s.clone().into_py(py),
355 HlxValue::Number(n) => n.into_py(py),
356 HlxValue::Bool(b) => b.into_py(py),
357 _ => format!("{:?}", value).into_py(py),
358 };
359 Some(obj)
360 })
361 } else {
362 None
363 }
364 }
365}
366#[pyfunction]
367fn parse(source: String) -> PyResult<PyHelixConfig> {
368 let config_result = crate::parse_and_validate(&source)
369 .map_err(|e| PyValueError::new_err(format!("Parse error: {}", e)))?;
370 let mut py_config = PyHelixConfig::new();
371 if let Ok(config_json) = serde_json::to_string(&config_result) {
372 if let Ok(value) = serde_json::from_str::<serde_json::Value>(&config_json) {
373 if let serde_json::Value::Object(map) = value {
374 for (k, v) in map {
375 let helix_value = match v {
376 serde_json::Value::String(s) => HlxValue::String(s),
377 serde_json::Value::Number(n) => {
378 if let Some(f) = n.as_f64() {
379 HlxValue::Number(f)
380 } else if let Some(i) = n.as_i64() {
381 HlxValue::Number(i as f64)
382 } else {
383 HlxValue::String(format!("{}", n))
384 }
385 }
386 serde_json::Value::Bool(b) => HlxValue::Bool(b),
387 serde_json::Value::Array(arr) => {
388 let mut helix_array = Vec::new();
389 for item in arr {
390 match item {
391 serde_json::Value::String(s) => {
392 helix_array.push(HlxValue::String(s))
393 }
394 serde_json::Value::Number(n) => {
395 if let Some(f) = n.as_f64() {
396 helix_array.push(HlxValue::Number(f));
397 }
398 }
399 serde_json::Value::Bool(b) => {
400 helix_array.push(HlxValue::Bool(b))
401 }
402 _ => helix_array.push(HlxValue::String(format!("{}", item))),
403 }
404 }
405 HlxValue::Array(helix_array)
406 }
407 serde_json::Value::Object(obj) => {
408 let mut helix_obj = HashMap::new();
409 for (obj_k, obj_v) in obj {
410 match obj_v {
411 serde_json::Value::String(s) => {
412 helix_obj.insert(obj_k, HlxValue::String(s));
413 }
414 serde_json::Value::Number(n) => {
415 if let Some(f) = n.as_f64() {
416 helix_obj.insert(obj_k, HlxValue::Number(f));
417 }
418 }
419 serde_json::Value::Bool(b) => {
420 helix_obj.insert(obj_k, HlxValue::Bool(b));
421 }
422 _ => {
423 helix_obj
424 .insert(obj_k, HlxValue::String(format!("{}", obj_v)));
425 }
426 }
427 }
428 HlxValue::Object(helix_obj)
429 }
430 serde_json::Value::Null => HlxValue::Null,
431 };
432 py_config.data.insert(k, helix_value);
433 }
434 }
435 }
436 }
437 Ok(py_config)
438}
439#[pyfunction]
440fn execute(
441 expression: String,
442 context: Option<HashMap<String, PyObject>>,
443) -> PyResult<PyObject> {
444 let rt = tokio::runtime::Runtime::new()
445 .map_err(|e| PyRuntimeError::new_err(
446 format!("Failed to create runtime: {}", e),
447 ))?;
448 rt.block_on(async {
449 let mut interpreter = HelixInterpreter::new()
450 .await
451 .map_err(|e| PyRuntimeError::new_err(
452 format!("Failed to create interpreter: {}", e),
453 ))?;
454 if let Some(ctx) = context {
455 for (key, value) in ctx {
456 let helix_value = Python::with_gil(|py| {
457 match value.extract::<String>(py) {
458 Ok(s) => HlxValue::String(s),
459 Err(_) => match value.extract::<f64>(py) {
460 Ok(n) => HlxValue::Number(n),
461 Err(_) => match value.extract::<bool>(py) {
462 Ok(b) => HlxValue::Bool(b),
463 Err(_) => HlxValue::String(format!("{:?}", value.bind(py))),
464 },
465 },
466 }
467 });
468 let helix_value_clone = helix_value.clone();
470 let types_value = match helix_value {
472 HlxValue::String(s) => crate::dna::atp::types::Value::String(s),
473 HlxValue::Number(n) => crate::dna::atp::types::Value::Number(n),
474 HlxValue::Bool(b) => crate::dna::atp::types::Value::Bool(b),
475 HlxValue::Array(arr) => crate::dna::atp::types::Value::Array(
476 arr.into_iter().map(|v| match v {
477 HlxValue::String(s) => crate::dna::atp::types::Value::String(s),
478 HlxValue::Number(n) => crate::dna::atp::types::Value::Number(n),
479 HlxValue::Bool(b) => crate::dna::atp::types::Value::Bool(b),
480 HlxValue::Null => crate::dna::atp::types::Value::Null,
481 _ => crate::dna::atp::types::Value::String(format!("{:?}", v)),
482 }).collect()
483 ),
484 HlxValue::Object(obj) => crate::dna::atp::types::Value::Object(
485 obj.into_iter().map(|(k, v)| (k, match v {
486 HlxValue::String(s) => crate::dna::atp::types::Value::String(s),
487 HlxValue::Number(n) => crate::dna::atp::types::Value::Number(n),
488 HlxValue::Bool(b) => crate::dna::atp::types::Value::Bool(b),
489 HlxValue::Null => crate::dna::atp::types::Value::Null,
490 _ => crate::dna::atp::types::Value::String(format!("{:?}", v)),
491 })).collect()
492 ),
493 HlxValue::Null => crate::dna::atp::types::Value::Null,
494 HlxValue::Duration(d) => crate::dna::atp::types::Value::Duration(d),
495 HlxValue::Reference(r) => crate::dna::atp::types::Value::Reference(r),
496 HlxValue::Identifier(i) => crate::dna::atp::types::Value::Identifier(i),
497 };
498 interpreter.set_variable(key.to_string(), helix_value_clone);
499 }
500 }
501 if let Some(value) = interpreter.get_variable(&expression) {
502 Python::with_gil(|py| {
503 let obj: PyObject = match value {
504 HlxValue::String(s) => s.clone().into_py(py),
505 HlxValue::Number(n) => n.into_py(py),
506 HlxValue::Bool(b) => b.into_py(py),
507 _ => format!("{:?}", value).into_py(py),
508 };
509 Ok(obj)
510 })
511 } else {
512 Python::with_gil(|py| {
513 Ok(format!("Executed: {}", expression).into_py(py))
514 })
515 }
516 })
517}
518#[pyfunction]
519fn load_file(file_path: String) -> PyResult<PyHelixConfig> {
520 let config_result = crate::load_file(&file_path)
521 .map_err(|e| PyValueError::new_err(format!("File load error: {}", e)))?;
522 let mut py_config = PyHelixConfig::new();
523 if let Ok(config_json) = serde_json::to_string(&config_result) {
524 if let Ok(value) = serde_json::from_str::<serde_json::Value>(&config_json) {
525 if let serde_json::Value::Object(map) = value {
526 for (k, v) in map {
527 let helix_value = match v {
528 serde_json::Value::String(s) => HlxValue::String(s),
529 serde_json::Value::Number(n) => {
530 if let Some(f) = n.as_f64() {
531 HlxValue::Number(f)
532 } else {
533 HlxValue::String(format!("{}", n))
534 }
535 }
536 serde_json::Value::Bool(b) => HlxValue::Bool(b),
537 serde_json::Value::Array(arr) => {
538 let mut helix_array = Vec::new();
539 for item in arr {
540 match item {
541 serde_json::Value::String(s) => {
542 helix_array.push(HlxValue::String(s))
543 }
544 serde_json::Value::Number(n) => {
545 if let Some(f) = n.as_f64() {
546 helix_array.push(HlxValue::Number(f));
547 }
548 }
549 serde_json::Value::Bool(b) => {
550 helix_array.push(HlxValue::Bool(b))
551 }
552 _ => helix_array.push(HlxValue::String(format!("{}", item))),
553 }
554 }
555 HlxValue::Array(helix_array)
556 }
557 serde_json::Value::Object(obj) => {
558 let mut helix_obj = HashMap::new();
559 for (obj_k, obj_v) in obj {
560 match obj_v {
561 serde_json::Value::String(s) => {
562 helix_obj.insert(obj_k, HlxValue::String(s));
563 }
564 serde_json::Value::Number(n) => {
565 if let Some(f) = n.as_f64() {
566 helix_obj.insert(obj_k, HlxValue::Number(f));
567 }
568 }
569 serde_json::Value::Bool(b) => {
570 helix_obj.insert(obj_k, HlxValue::Bool(b));
571 }
572 _ => {
573 helix_obj
574 .insert(obj_k, HlxValue::String(format!("{}", obj_v)));
575 }
576 }
577 }
578 HlxValue::Object(helix_obj)
579 }
580 serde_json::Value::Null => HlxValue::Null,
581 };
582 py_config.data.insert(k, helix_value);
583 }
584 }
585 }
586 }
587 Ok(py_config)
588}
589#[pymodule]
590fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
591 m.add_class::<Value>()?;
592 m.add_class::<PyExecutionContext>()?;
593 m.add_class::<PyOperatorRegistry>()?;
594 m.add_class::<PyHelixConfig>()?;
595 m.add_class::<PyHelixInterpreter>()?;
596 m.add_function(wrap_pyfunction_bound!(parse, m)?)?;
597 m.add_function(wrap_pyfunction_bound!(execute, m)?)?;
598 m.add_function(wrap_pyfunction_bound!(load_file, m)?)?;
599 Ok(())
600}