Files
orchid/orchid-std/src/std/string/str_atom.rs

196 lines
5.6 KiB
Rust

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<String>;
}
impl AtomMethod for StringGetValMethod {
const NAME: &str = "std::string_get_val";
}
#[derive(Clone)]
pub struct StrAtom(Rc<String>);
impl Atomic for StrAtom {
type Variant = OwnedVariant;
type Data = ();
fn reg_reqs() -> MethodSetBuilder<Self> {
MethodSetBuilder::new()
.handle::<StringGetValMethod>()
.handle::<ToStringMethod>()
.handle::<ProtocolMethod>()
}
}
impl StrAtom {
pub fn new(str: Rc<String>) -> 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::<String>().await))
}
}
impl Supports<StringGetValMethod> for StrAtom {
async fn handle<'a>(
&self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: StringGetValMethod,
) -> io::Result<Receipt<'a>> {
hand.reply(&req, &self.0).await
}
}
impl Supports<ToStringMethod> for StrAtom {
async fn handle<'a>(
&self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: ToStringMethod,
) -> io::Result<Receipt<'a>> {
hand.reply(&req, &self.0).await
}
}
impl Supports<ProtocolMethod> for StrAtom {
async fn handle<'a>(
&self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: ProtocolMethod,
) -> io::Result<Receipt<'a>> {
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<Self> {
MethodSetBuilder::new().handle::<ProtocolMethod>().handle::<ToStringMethod>()
}
}
impl From<IStr> 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::<String>().await;
Self(is(&s).await)
}
}
impl TryFromExpr for IntStrAtom {
async fn try_from_expr(expr: Expr) -> OrcRes<Self> {
Ok(IntStrAtom(es(TAtom::<IntStrAtom>::try_from_expr(expr).await?.value).await))
}
}
impl Supports<ToStringMethod> for IntStrAtom {
async fn handle<'a>(
&self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: ToStringMethod,
) -> io::Result<Receipt<'a>> {
hand.reply(&req, &self.0.rc()).await
}
}
impl Supports<ProtocolMethod> for IntStrAtom {
async fn handle<'a>(
&self,
hand: Box<dyn ReqHandle<'a> + '_>,
req: ProtocolMethod,
) -> io::Result<Receipt<'a>> {
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<StrAtom>),
Int(TAtom<IntStrAtom>),
}
impl OrcString {
pub async fn get_string(&self) -> Rc<String> {
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<OrcString> {
if let Ok(v) = TAtom::<StrAtom>::try_from_expr(expr.clone()).await {
return Ok(OrcString { kind: OrcStringKind::Val(v) });
}
match TAtom::<IntStrAtom>::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())),
}
}
}