use std::borrow::Cow; use std::io; use std::ops::Deref; use std::pin::Pin; use std::rc::Rc; use futures::AsyncWrite; use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::{Encode, Request}; use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::format::{FmtCtx, FmtUnit}; use orchid_base::interner::{IStr, es, is}; use orchid_base::name::Sym; use orchid_base::reqnot::{Receipt, ReqHandle, ReqHandleExt}; use orchid_base::sym; use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TAtom}; use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant}; use orchid_extension::conv::TryFromExpr; use orchid_extension::expr::Expr; use orchid_extension::gen_expr::sym_ref; use crate::std::protocol::types::{GetImpl, ProtocolMethod}; use crate::std::string::to_string::ToStringMethod; #[derive(Copy, Clone, Debug, Coding, Hierarchy)] pub struct StringGetValMethod; impl Request for StringGetValMethod { type Response = Rc; } impl AtomMethod for StringGetValMethod { const NAME: &str = "std::string_get_val"; } #[derive(Clone)] pub struct StrAtom(Rc); impl Atomic for StrAtom { type Variant = OwnedVariant; type Data = (); fn reg_reqs() -> MethodSetBuilder { MethodSetBuilder::new() .handle::() .handle::() .handle::() } } impl StrAtom { pub fn new(str: Rc) -> Self { Self(str) } } impl Deref for StrAtom { type Target = str; fn deref(&self) -> &Self::Target { &self.0 } } impl OwnedAtom for StrAtom { type Refs = (); async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } async fn serialize(&self, sink: Pin<&mut (impl AsyncWrite + ?Sized)>) -> Self::Refs { self.deref().encode(sink).await.unwrap() } async fn print_atom<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { format!("{:?}", &*self.0).into() } async fn deserialize(mut ctx: impl DeserializeCtx, _: Self::Refs) -> Self { Self::new(Rc::new(ctx.read::().await)) } } impl Supports for StrAtom { async fn handle<'a>( &self, hand: Box + '_>, req: StringGetValMethod, ) -> io::Result> { hand.reply(&req, &self.0).await } } impl Supports for StrAtom { async fn handle<'a>( &self, hand: Box + '_>, req: ToStringMethod, ) -> io::Result> { hand.reply(&req, &self.0).await } } impl Supports for StrAtom { async fn handle<'a>( &self, hand: Box + '_>, req: ProtocolMethod, ) -> io::Result> { match req { ProtocolMethod::GetTagId(req) => hand.reply(&req, &sym!(std::string::StrAtom).to_api()).await, ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => { let name = Sym::from_api(key).await; let val = if name == sym!(std::ops::add) { sym_ref(sym!(std::string::concat)) } else { return hand.reply(req, &None).await; }; hand.reply(req, &Some(val.create().await.serialize().await)).await }, } } } #[derive(Debug, Clone)] pub struct IntStrAtom(pub(crate) IStr); impl Atomic for IntStrAtom { type Variant = OwnedVariant; type Data = orchid_api::TStr; fn reg_reqs() -> MethodSetBuilder { MethodSetBuilder::new().handle::().handle::() } } impl From for IntStrAtom { fn from(value: IStr) -> Self { Self(value) } } impl OwnedAtom for IntStrAtom { type Refs = (); async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.0.to_api()) } async fn print_atom<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { format!("{:?}i", &*self.0).into() } async fn serialize(&self, write: Pin<&mut (impl AsyncWrite + ?Sized)>) { self.0.encode(write).await.unwrap() } async fn deserialize(mut dctx: impl DeserializeCtx, _: ()) -> Self { let s = dctx.decode::().await; Self(is(&s).await) } } impl TryFromExpr for IntStrAtom { async fn try_from_expr(expr: Expr) -> OrcRes { Ok(IntStrAtom(es(TAtom::::try_from_expr(expr).await?.value).await)) } } impl Supports for IntStrAtom { async fn handle<'a>( &self, hand: Box + '_>, req: ToStringMethod, ) -> io::Result> { hand.reply(&req, &self.0.rc()).await } } impl Supports for IntStrAtom { async fn handle<'a>( &self, hand: Box + '_>, req: ProtocolMethod, ) -> io::Result> { match req { ProtocolMethod::GetTagId(req) => hand.reply(&req, &sym!(std::string::IntStrAtom).to_api()).await, ProtocolMethod::GetImpl(ref req @ GetImpl(key)) => { let name = Sym::from_api(key).await; let val = if name == sym!(std::ops::add) { sym_ref(sym!(std::string::concat)) } else { return hand.reply(req, &None).await; }; hand.reply(req, &Some(val.create().await.serialize().await)).await }, } } } #[derive(Clone)] pub struct OrcString { kind: OrcStringKind, } #[derive(Clone)] pub enum OrcStringKind { Val(TAtom), Int(TAtom), } impl OrcString { pub async fn get_string(&self) -> Rc { match &self.kind { OrcStringKind::Int(tok) => es(**tok).await.rc(), OrcStringKind::Val(atom) => atom.request(StringGetValMethod).await, } } } impl TryFromExpr for OrcString { async fn try_from_expr(expr: Expr) -> OrcRes { if let Ok(v) = TAtom::::try_from_expr(expr.clone()).await { return Ok(OrcString { kind: OrcStringKind::Val(v) }); } match TAtom::::try_from_expr(expr).await { Ok(t) => Ok(OrcString { kind: OrcStringKind::Int(t) }), Err(e) => Err(mk_errv(is("A string was expected").await, "", e.pos_iter())), } } }