use anyhow::Result;
use arcstr::ArcStr;
use ahash::AHashMap;
use graphix_compiler::{env::Env, ExecCtx};
use graphix_package::{CustomDisplay, IndexSet, MainThreadHandle, Package};
use graphix_rt::{CompExp, GXExt, GXHandle, GXRt};
use netidx_core::path::Path;
use tokio::sync::oneshot;
pub(crate) struct RegisterResult {
pub root: ArcStr,
pub main_program: Option<&'static str>,
}
pub(crate) fn register<X: GXExt>(
ctx: &mut ExecCtx<GXRt<X>, X::UserEvent>,
modules: &mut AHashMap<Path, ArcStr>,
) -> Result<RegisterResult> {
let mut root_mods = IndexSet::new();
{{#each deps}}
{{this.crate_name}}::P::register(ctx, modules, &mut root_mods)?;
{{/each}}
let mut parts = Vec::new();
for name in &root_mods {
if name == "core" {
parts.push(format!("mod core;\nuse core"));
} else {
parts.push(format!("mod {name}"));
}
}
let mut main_program = None;
{{#each deps}}
if let Some(m) = <{{this.crate_name}}::P as Package<X>>::main_program() {
main_program = Some(m);
}
{{/each}}
Ok(RegisterResult {
root: ArcStr::from(parts.join(";\n")),
main_program,
})
}
pub(crate) struct Cdc<X: GXExt> {
pub stop: oneshot::Receiver<()>,
pub custom: Box<dyn CustomDisplay<X>>,
}
pub(crate) enum CustomResult<X: GXExt> {
Custom(Cdc<X>),
NotCustom(CompExp<X>),
}
pub(crate) async fn maybe_init_custom<X: GXExt>(
gx: &GXHandle<X>,
env: &Env,
e: CompExp<X>,
run_on_main: &MainThreadHandle,
) -> Result<CustomResult<X>> {
{{#each deps}}
if {{this.crate_name}}::P::is_custom(gx, env, &e) {
let (tx, rx) = oneshot::channel();
return {{this.crate_name}}::P::init_custom(gx, env, tx, e, run_on_main.clone()).await
.map(|custom| CustomResult::Custom(Cdc { stop: rx, custom }));
}
{{/each}}
Ok(CustomResult::NotCustom(e))
}