use std::borrow::Cow; use std::pin::Pin; use futures::AsyncWrite; use orchid_api_traits::Encode; use orchid_base::error::mk_errv; use orchid_base::sym; use orchid_extension::atom::{Atomic, ForeignAtom, TAtom}; use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant}; use orchid_extension::context::i; use orchid_extension::conv::{ToExpr, TryFromExpr}; use orchid_extension::expr::{Expr, ExprHandle}; use orchid_extension::gen_expr::{call, sym_ref}; use orchid_extension::tree::{GenMember, cnst, fun, prefix}; 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; self.0.iter().cloned().collect() } } pub struct OrcOpt(pub Option); impl TryFromExpr for OrcOpt { async fn try_from_expr(expr: Expr) -> orchid_base::error::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_ref(sym!(std::option::some; i())), [val.to_gen().await]) } else { sym_ref(sym!(std::option::none; i())) } } } pub fn gen_option_lib() -> Vec { prefix("std::option", [ cnst(true, "none", OptAtom(None)), fun(true, "some", async |ex: Expr| 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( i().i("Unwrapped std::option::none").await, msg.get_string().await.as_str(), [opt.pos()], )), } }), ]) }