use std::borrow::Cow; use std::rc::Rc; use futures::future::LocalBoxFuture; use never::Never; use orchid_base::{Receipt, ReqHandle, ReqHandleExt}; use crate::gen_expr::{GExpr, new_atom, serialize}; use crate::std_reqs::RunCommand; use crate::{Atomic, MethodSetBuilder, OwnedAtom, OwnedVariant, Supports, ToExpr}; pub trait AsyncFnDyn { fn call<'a>(&'a self) -> LocalBoxFuture<'a, Option>; } impl Option> AsyncFnDyn for T { fn call<'a>(&'a self) -> LocalBoxFuture<'a, Option> { Box::pin(async { (self)().await }) } } #[derive(Clone)] pub struct CmdAtom(Rc); impl Atomic for CmdAtom { type Data = (); type Variant = OwnedVariant; fn reg_methods() -> MethodSetBuilder { MethodSetBuilder::new().handle::() } } impl Supports for CmdAtom { async fn handle<'a>( &self, hand: Box + '_>, req: RunCommand, ) -> std::io::Result> { let reply = self.0.call().await; match reply { None => hand.reply(&req, &None).await, Some(next) => hand.reply(&req, &Some(serialize(next).await)).await, } } } impl OwnedAtom for CmdAtom { type Refs = Never; async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } } pub fn cmd(f: impl AsyncFn() -> Option + Clone + 'static) -> GExpr { new_atom(CmdAtom(Rc::new(async move || match f().await { None => None, Some(r) => Some(r.to_gen().await), }))) }