use std::borrow::Cow; use std::io; use std::ops::Deref; use std::sync::Arc; use orchid_api_derive::Coding; use orchid_api_traits::{Encode, Request}; use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::intern; use orchid_base::interner::{Tok, intern}; use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TypAtom}; use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant}; use orchid_extension::conv::TryFromExpr; use orchid_extension::expr::Expr; use orchid_extension::system::SysCtx; #[derive(Copy, Clone, Coding)] pub struct StringGetVal; impl Request for StringGetVal { type Response = Arc; } impl AtomMethod for StringGetVal { const NAME: &str = "std::string_get_val"; } impl Supports for StrAtom { fn handle(&self, _: SysCtx, _: StringGetVal) -> ::Response { self.0.clone() } } #[derive(Clone)] pub struct StrAtom(Arc); impl Atomic for StrAtom { type Variant = OwnedVariant; type Data = (); fn reg_reqs() -> MethodSetBuilder { MethodSetBuilder::new().handle::() } } impl StrAtom { pub fn new(str: Arc) -> Self { Self(str) } pub fn value(&self) -> Arc { self.0.clone() } } impl Deref for StrAtom { type Target = str; fn deref(&self) -> &Self::Target { &self.0 } } impl OwnedAtom for StrAtom { type Refs = (); fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } fn serialize(&self, _: SysCtx, sink: &mut (impl io::Write + ?Sized)) -> Self::Refs { self.deref().encode(sink) } fn deserialize(mut ctx: impl DeserializeCtx, _: Self::Refs) -> Self { Self::new(Arc::new(ctx.read::())) } } #[derive(Debug, Clone)] pub struct IntStrAtom(Tok); impl Atomic for IntStrAtom { type Variant = OwnedVariant; type Data = orchid_api::TStr; fn reg_reqs() -> MethodSetBuilder { MethodSetBuilder::new() } } impl From> for IntStrAtom { fn from(value: Tok) -> Self { Self(value) } } impl OwnedAtom for IntStrAtom { type Refs = (); fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.0.to_api()) } fn print(&self, _ctx: SysCtx) -> String { format!("{:?}i", *self.0) } fn serialize(&self, _: SysCtx, write: &mut (impl io::Write + ?Sized)) { self.0.encode(write) } fn deserialize(ctx: impl DeserializeCtx, _: ()) -> Self { Self(intern(&ctx.decode::())) } } #[derive(Clone)] pub enum OrcString<'a> { Val(TypAtom<'a, StrAtom>), Int(TypAtom<'a, IntStrAtom>), } impl OrcString<'_> { pub fn get_string(&self) -> Arc { match &self { Self::Int(tok) => Tok::from_api(tok.value).arc(), Self::Val(atom) => atom.request(StringGetVal), } } } impl TryFromExpr for OrcString<'static> { fn try_from_expr(expr: Expr) -> OrcRes> { if let Ok(v) = TypAtom::::try_from_expr(expr.clone()) { return Ok(OrcString::Val(v)); } match TypAtom::::try_from_expr(expr) { Ok(t) => Ok(OrcString::Int(t)), Err(e) => Err(mk_errv(intern!(str: "A string was expected"), "", e.pos_iter())), } } }