use std::borrow::Cow; use std::pin::Pin; use futures::AsyncWrite; use orchid_api_traits::Encode; use orchid_base::{is, mk_errv, sym}; use orchid_extension::{ToExpr, TryFromExpr}; use orchid_extension::{Expr, ExprHandle}; use orchid_extension::gen_expr::{call, new_atom}; use orchid_extension::tree::{GenMember, cnst, fun, prefix}; use orchid_extension::{Atomic, DeserializeCtx, ForeignAtom, OwnedAtom, OwnedVariant, TAtom}; use crate::{OrcString, api}; #[derive(Clone)] pub struct OptAtom(Option); impl Atomic for OptAtom { type Data = Option; type Variant = OwnedVariant; } impl OwnedAtom for OptAtom { type Refs = Vec; async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.0.as_ref().map(|ex| ex.handle().ticket())) } async fn deserialize(mut ctx: impl DeserializeCtx, refs: Self::Refs) -> Self { Self(ctx.read::().await.then(|| refs.into_iter().next().unwrap())) } async fn serialize(&self, write: Pin<&mut (impl AsyncWrite + ?Sized)>) -> Self::Refs { self.0.is_some().encode(write).await.unwrap(); self.0.iter().cloned().collect() } } pub struct OrcOpt(pub Option); impl TryFromExpr for OrcOpt { async fn try_from_expr(expr: Expr) -> orchid_base::OrcRes { let atom = TAtom::::try_from_expr(expr).await?; match atom.value { None => Ok(OrcOpt(None)), Some(tk) => Ok(OrcOpt(Some( T::try_from_expr(Expr::from_handle(ExprHandle::from_ticket(tk).await)).await?, ))), } } } impl ToExpr for OrcOpt { async fn to_gen(self) -> orchid_extension::gen_expr::GExpr { if let Some(val) = self.0 { call(sym!(std::option::some), val).await } else { sym!(std::option::none).to_gen().await } } } pub fn gen_option_lib() -> Vec { prefix("std::option", [ cnst(true, "none", new_atom(OptAtom(None))), fun(true, "some", async |ex: Expr| new_atom(OptAtom(Some(ex)))), fun(true, "expect", async |opt: ForeignAtom, msg: OrcString| { match OrcOpt::try_from_expr(opt.clone().ex()).await? { OrcOpt(Some(ex)) => Ok::(ex), OrcOpt(None) => Err(mk_errv(is("Unwrapped std::option::none").await, msg.get_string().await.as_str(), [ opt.pos(), ])), } }), ]) }