use super::env::Env;
use super::error::{CapabilityPlannerError, RunError};
use super::graph::CapabilityGraph;
use super::provider::{ProviderBox, ShutdownHook};
use super::set::FromEnv;
use crate::kernel::Effect;
use crate::runtime::run_blocking;
use std::sync::Arc;
#[inline]
pub fn run<A, E>(app: Effect<A, E, ()>) -> Result<A, RunError<E>> {
run_blocking(app, ()).map_err(RunError::Effect)
}
pub fn run_with<A, E, R, I>(providers: I, app: Effect<A, E, R>) -> Result<A, RunError<E>>
where
I: IntoIterator<Item = ProviderBox>,
R: FromEnv,
{
let (env, hooks) = build_env_with_hooks(providers).map_err(RunError::Planner)?;
R::verify(&env).map_err(RunError::Capability)?;
let runtime = R::from_env(env);
let result = run_blocking(app, runtime).map_err(RunError::Effect);
for hook in hooks.into_iter().rev() {
hook.shutdown();
}
result
}
pub fn build_env<I>(providers: I) -> Result<Env, CapabilityPlannerError>
where
I: IntoIterator<Item = ProviderBox>,
{
build_env_with_hooks(providers).map(|(env, _)| env)
}
fn build_env_with_hooks<I>(
providers: I,
) -> Result<(Env, Vec<Arc<dyn ShutdownHook>>), CapabilityPlannerError>
where
I: IntoIterator<Item = ProviderBox>,
{
let mut graph = CapabilityGraph::new();
let mut hooks = Vec::new();
for p in providers {
if let Some(h) = p.0.shutdown_hook() {
hooks.push(h);
}
graph = graph.add(p.0);
}
let env = graph.build()?;
Ok((env, hooks))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::provide;
use crate::{Effect, caps, effect, run_with};
#[allow(dead_code)]
#[::id_effect::capability(u32)]
struct RunCap;
#[derive(::id_effect::ProviderSpecDerive)]
#[provides(RunCapKey)]
struct RunCapLive;
impl RunCapLive {
#[allow(clippy::new_ret_no_self)]
fn new() -> u32 {
7
}
}
#[test]
fn build_env_materializes_capability_env() {
let env = build_env([provide!(RunCapLive)]).expect("env");
assert_eq!(*env.get::<RunCapKey>(), 7);
}
#[test]
fn run_with_executes_and_shuts_down() {
let app: Effect<u32, (), caps!(RunCapKey)> = effect!(|r| { *~RunCapKey });
assert_eq!(run_with([provide!(RunCapLive)], app).expect("run"), 7);
}
}