Skip to content

Commit

Permalink
update dynamic
Browse files Browse the repository at this point in the history
  • Loading branch information
victorteokw committed Dec 6, 2024
1 parent 1a648be commit afef3ce
Show file tree
Hide file tree
Showing 27 changed files with 1,228 additions and 1,053 deletions.
14 changes: 9 additions & 5 deletions src/app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ::teo::prelude::{RuntimeVersion, App as TeoApp, Entrance, transaction};
use teo_result::Error;
use tokio::runtime::Builder;

use crate::{dynamic::{py_class_lookup_map::PYClassLookupMap, synthesize_dynamic_python_classes}, namespace::namespace::Namespace, utils::{check_callable::check_callable, is_coroutine::is_coroutine}};
use crate::{dynamic::{synthesize_dynamic_python_classes, DynamicClasses, QueryDynamicClasses}, namespace::namespace::Namespace, utils::{check_callable::check_callable, is_coroutine::is_coroutine}};

#[pyclass]
#[derive(Clone)]
Expand Down Expand Up @@ -48,14 +48,16 @@ impl App {

fn setup<'p>(&mut self, py: Python<'p>, callback: PyObject) -> PyResult<()> {
check_callable(&callback.bind(py))?;
let map = PYClassLookupMap::from_app_data(self.teo_app.app_data());
let app_data = self.teo_app.app_data().clone();
self.teo_app.setup(move |ctx: transaction::Ctx| {
let app_data = app_data.clone();
let callback = Python::with_gil(|py| {
callback.clone_ref(py)
});
async move {
let dynamic_classes = DynamicClasses::retrieve(&app_data)?;
let transformed = Python::with_gil(|py| {
let transformed_py = callback.call1(py, (map.teo_transaction_ctx_to_py_ctx_object(py, ctx, "")?,))?;
let transformed_py = callback.call1(py, (dynamic_classes.teo_transaction_ctx_to_py_ctx_object(py, ctx, "")?,))?;
let is_coroutine = is_coroutine(&transformed_py)?;
Ok::<_, Error>((transformed_py, is_coroutine))
})?;
Expand All @@ -74,14 +76,16 @@ impl App {
#[pyo3(signature = (name, desc, callback))]
fn program<'p>(&mut self, py: Python<'p>, name: &str, desc: Option<&str>, callback: PyObject) -> PyResult<()> {
check_callable(&callback.bind(py))?;
let map = PYClassLookupMap::from_app_data(self.teo_app.app_data());
let app_data = self.teo_app.app_data().clone();
self.teo_app.program(name, desc, move |ctx: transaction::Ctx| {
let app_data = app_data.clone();
let callback = Python::with_gil(|py| {
callback.clone_ref(py)
});
async move {
let dynamic_classes = DynamicClasses::retrieve(&app_data)?;
let transformed = Python::with_gil(|py| {
let transformed_py = callback.call1(py, (map.teo_transaction_ctx_to_py_ctx_object(py, ctx, "")?,))?;
let transformed_py = callback.call1(py, (dynamic_classes.teo_transaction_ctx_to_py_ctx_object(py, ctx, "")?,))?;
let is_coroutine = is_coroutine(&transformed_py)?;
Ok::<_, Error>((transformed_py, is_coroutine))
})?;
Expand Down
56 changes: 56 additions & 0 deletions src/dynamic/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::collections::BTreeMap;
use pyo3::PyObject;
use super::{CreateDynamicClasses, DynamicClasses, FetchDynamicClasses, QueryDynamicClasses};

pub struct DynamicClassesBuilder {
ctxs: BTreeMap<String, PyObject>,
classes: BTreeMap<String, PyObject>,
objects: BTreeMap<String, PyObject>,
}

impl DynamicClassesBuilder {

pub fn new() -> Self {
Self {
ctxs: BTreeMap::new(),
classes: BTreeMap::new(),
objects: BTreeMap::new(),
}
}

pub fn build(self) -> DynamicClasses {
DynamicClasses::new(self.ctxs, self.classes, self.objects)
}
}

impl FetchDynamicClasses for DynamicClassesBuilder {

fn ctxs(&self) -> &BTreeMap<String, PyObject> {
&self.ctxs
}

fn classes(&self) -> &BTreeMap<String, PyObject> {
&self.classes
}

fn objects(&self) -> &BTreeMap<String, PyObject> {
&self.objects
}
}

impl CreateDynamicClasses for DynamicClassesBuilder {

fn ctxs_mut(&mut self) -> &mut BTreeMap<String, PyObject> {
&mut self.ctxs
}

fn classes_mut(&mut self) -> &mut BTreeMap<String, PyObject> {
&mut self.classes
}

fn objects_mut(&mut self) -> &mut BTreeMap<String, PyObject> {
&mut self.objects
}
}

impl QueryDynamicClasses for DynamicClassesBuilder { }
78 changes: 78 additions & 0 deletions src/dynamic/create.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use std::{collections::BTreeMap, ffi::CStr};
use pyo3::{exceptions::PyRuntimeError, types::{PyAnyMethods, PyCFunction, PyDict}, PyErr, PyObject, PyResult, Python};
use super::fetch::FetchDynamicClasses;

static INIT_ERROR_MESSAGE_C: &CStr = c"class is not initialized";
static INIT_ERROR_MESSAGE: &str = "class is not initialized";

pub trait CreateDynamicClasses: FetchDynamicClasses {

fn ctxs_mut(&mut self) -> &mut BTreeMap<String, PyObject>;

fn classes_mut(&mut self) -> &mut BTreeMap<String, PyObject>;

fn objects_mut(&mut self) -> &mut BTreeMap<String, PyObject>;

fn ctx_or_create(&mut self, name: &str, py: Python<'_>) -> PyResult<PyObject> {
let builtins = py.import("builtins")?;
let py_type = builtins.getattr("type")?;
let py_object = builtins.getattr("object")?;
let dict = PyDict::new(py);
dict.set_item("__module__", "teo.models")?;
let init = PyCFunction::new_closure(py, Some(c"__init__"), None, |args, _kwargs| {
let slf = args.get_item(0)?;
let initialized: bool = slf.getattr("__teo_initialized__")?.extract()?;
if initialized {
Ok(())
} else {
Err::<(), PyErr>(PyRuntimeError::new_err(INIT_ERROR_MESSAGE))
}
})?;
dict.set_item("__init__", init)?;
let result = py_type.call1((name, (py_object,), dict))?.unbind();
self.ctxs_mut().insert(name.to_owned(), result.clone_ref(py));
Ok(result)
}

fn class_or_create(&mut self, name: &str, py: Python<'_>) -> PyResult<PyObject> {
let builtins = py.import("builtins")?;
let py_type = builtins.getattr("type")?;
let py_object = builtins.getattr("object")?;
let dict = PyDict::new(py);
dict.set_item("__module__", "teo.models")?;
let init = PyCFunction::new_closure(py, Some(c"__init__"), Some(INIT_ERROR_MESSAGE_C), |args, _kwargs| {
let slf = args.get_item(0)?;
let initialized: bool = slf.getattr("__teo_initialized__")?.extract()?;
if initialized {
Ok(())
} else {
Err::<(), PyErr>(PyRuntimeError::new_err(INIT_ERROR_MESSAGE))
}
})?;
dict.set_item("__init__", init)?;
let result = py_type.call1((name, (py_object,), dict))?.unbind();
self.classes_mut().insert(name.to_owned(), result.clone_ref(py));
Ok(result)
}

fn object_or_create(&mut self, name: &str, py: Python<'_>) -> PyResult<PyObject> {
let builtins = py.import("builtins")?;
let py_type = builtins.getattr("type")?;
let py_object = builtins.getattr("object")?;
let dict = PyDict::new(py);
dict.set_item("__module__", "teo.models")?;
let init = PyCFunction::new_closure(py, Some(c"__init__"), Some(INIT_ERROR_MESSAGE_C), |args, _kwargs| {
let slf = args.get_item(0)?;
let initialized: bool = slf.getattr("__teo_initialized__")?.extract()?;
if initialized {
Ok(())
} else {
Err::<(), PyErr>(PyRuntimeError::new_err(INIT_ERROR_MESSAGE))
}
})?;
dict.set_item("__init__", init)?;
let result = py_type.call1((name, (py_object,), dict))?.unbind();
self.objects_mut().insert(name.to_owned(), result.clone_ref(py));
Ok(result)
}
}
62 changes: 62 additions & 0 deletions src/dynamic/dynamic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::{collections::BTreeMap, sync::Arc};
use pyo3::{exceptions::PyException, PyObject, PyResult};
use teo::prelude::app::data::AppData;
use super::{fetch::FetchDynamicClasses, query::QueryDynamicClasses};

#[derive(Clone)]
pub struct DynamicClasses {
inner: Arc<Inner>,
}

struct Inner {
ctxs: BTreeMap<String, PyObject>,
classes: BTreeMap<String, PyObject>,
objects: BTreeMap<String, PyObject>,
}

impl DynamicClasses {

pub fn retrieve(app_data: &AppData) -> PyResult<Self> {
let reference = app_data.dynamic_classes()?;
let dynamic_classes: Option<&Self> = reference.downcast_ref();
match dynamic_classes {
Some(dynamic_classes) => Ok(dynamic_classes.clone()),
None => Err(PyException::new_err("The dynamic classes attached on the app data is of wrong type")),
}
}

pub fn attach(&self, app_data: AppData) -> PyResult<()> {
Ok(app_data.set_dynamic_classes(Arc::new(self.clone()))?)
}

pub fn new(
ctxs: BTreeMap<String, PyObject>,
classes: BTreeMap<String, PyObject>,
objects: BTreeMap<String, PyObject>
) -> Self {
Self {
inner: Arc::new(Inner {
ctxs,
classes,
objects,
}),
}
}
}

impl FetchDynamicClasses for DynamicClasses {

fn ctxs(&self) -> &BTreeMap<String, PyObject> {
&self.inner.ctxs
}

fn classes(&self) -> &BTreeMap<String, PyObject> {
&self.inner.classes
}

fn objects(&self) -> &BTreeMap<String, PyObject> {
&self.inner.objects
}
}

impl QueryDynamicClasses for DynamicClasses { }
29 changes: 29 additions & 0 deletions src/dynamic/fetch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::collections::BTreeMap;
use pyo3::{PyObject, PyResult, Python};

pub trait FetchDynamicClasses {

fn ctxs(&self) -> &BTreeMap<String, PyObject>;

fn classes(&self) -> &BTreeMap<String, PyObject>;

fn objects(&self) -> &BTreeMap<String, PyObject>;

fn ctx(&self, name: &str) -> PyResult<Option<PyObject>> {
Python::with_gil(|py| {
Ok(self.ctxs().get(name).map(|o| o.clone_ref(py)))
})
}

fn class(&self, name: &str) -> PyResult<Option<PyObject>> {
Python::with_gil(|py| {
Ok(self.classes().get(name).map(|o| o.clone_ref(py)))
})
}

fn object(&self, name: &str) -> PyResult<Option<PyObject>> {
Python::with_gil(|py| {
Ok(self.objects().get(name).map(|o| o.clone_ref(py)))
})
}
}
Loading

0 comments on commit afef3ce

Please sign in to comment.