use std::borrow::Cow; use std::io; use std::time::Instant; use chrono::TimeDelta; use never::Never; use orchid_api::ExprTicket; use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; use orchid_base::{Numeric, OrcRes, Receipt, ReqHandle, ReqHandleExt}; use orchid_extension::gen_expr::{GExpr, call, new_atom}; use orchid_extension::std_reqs::{AsDuration, RunCommand}; use orchid_extension::tree::{GenMember, fun, prefix}; use orchid_extension::{ Atomic, Expr, MethodSetBuilder, OwnedAtom, OwnedVariant, Supports, TAtom, ThinAtom, ThinVariant, ToExpr, TryFromExpr, sys_req, }; use ordered_float::NotNan; use crate::std::std_system::StdReq; use crate::{Float, Int, Num, StdSystem}; #[derive(Clone, Copy, Debug, Coding, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Hierarchy)] #[extends(StdReq)] pub struct CreateDT(pub OrcDT); impl Request for CreateDT { type Response = ExprTicket; } #[derive(Clone, Copy, Debug, Coding, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct OrcDT(pub TimeDelta); impl Atomic for OrcDT { type Variant = ThinVariant; type Data = Self; } impl ThinAtom for OrcDT {} impl ToExpr for OrcDT { async fn to_gen(self) -> GExpr { Expr::deserialize(sys_req::(CreateDT(self)).await).await.to_gen().await } } impl TryFromExpr for OrcDT { async fn try_from_expr(expr: Expr) -> OrcRes { Ok(TAtom::::try_from_expr(expr).await?.value) } } impl Supports for OrcDT { async fn handle<'a>( &self, hand: Box + '_>, req: AsDuration, ) -> std::io::Result> { hand.reply(&req, &self.0.to_std().unwrap()).await } } #[derive(Clone)] pub struct InstantAtom(Instant); impl Atomic for InstantAtom { type Variant = OwnedVariant; type Data = (); } impl OwnedAtom for InstantAtom { type Refs = Never; async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } } #[derive(Clone)] struct Now(Expr); impl Atomic for Now { type Variant = OwnedVariant; type Data = (); fn reg_methods() -> MethodSetBuilder { MethodSetBuilder::new().handle::() } } impl OwnedAtom for Now { type Refs = Never; async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) } } impl Supports for Now { async fn handle<'a>( &self, hand: Box + '_>, req: RunCommand, ) -> io::Result> { let cont = call(self.0.clone(), new_atom(InstantAtom(Instant::now()))).await.serialize().await; hand.reply(&req, &Some(cont)).await } } pub fn gen_time_lib() -> Vec { prefix("std::time", [ fun(true, "weeks", async |amount: Int| new_atom(OrcDT(TimeDelta::weeks(amount.0)))), fun(true, "num_weeks", async |amount: TAtom| Int(amount.0.num_weeks())), fun(true, "days", async |amount: Int| new_atom(OrcDT(TimeDelta::days(amount.0)))), fun(true, "num_days", async |amount: TAtom| Int(amount.0.num_days())), fun(true, "hours", async |amount: Int| new_atom(OrcDT(TimeDelta::hours(amount.0)))), fun(true, "num_hours", async |amount: TAtom| Int(amount.0.num_hours())), fun(true, "minutes", async |amount: Int| new_atom(OrcDT(TimeDelta::minutes(amount.0)))), fun(true, "num_minutes", async |amount: TAtom| Int(amount.0.num_minutes())), fun(true, "secs", async |amount: Num| { new_atom(OrcDT(match amount.0 { Numeric::Int(i) => TimeDelta::seconds(i), Numeric::Float(f) => TimeDelta::new(f.floor() as i64, (f.fract() * 1_000_000_000_f64).floor() as u32).unwrap(), })) }), fun(true, "num_secs", async |amount: TAtom| Int(amount.0.num_seconds())), fun(true, "as_secs", async |amount: TAtom| { Float(NotNan::new(amount.0.as_seconds_f64()).unwrap()) }), fun(true, "milis", async |amount: Int| new_atom(OrcDT(TimeDelta::milliseconds(amount.0)))), fun(true, "num_millis", async |amount: TAtom| Int(amount.0.num_milliseconds())), fun(true, "nanos", async |amount: Int| new_atom(OrcDT(TimeDelta::nanoseconds(amount.0)))), fun(true, "num_nanos", async |amount: TAtom| Int(amount.0.num_nanoseconds().unwrap())), fun(true, "now", async |cb: Expr| new_atom(Now(cb))), ]) }