Pending a correct test of request cancellation
This commit is contained in:
@@ -3,12 +3,15 @@ use std::io;
|
||||
use std::rc::Rc;
|
||||
|
||||
use never::Never;
|
||||
use orchid_base::{ReqHandleExt, fmt, is, mk_errv};
|
||||
use orchid_base::{Receipt, ReqHandle, ReqHandleExt, fmt, is, mk_errv};
|
||||
use orchid_extension::gen_expr::{bot, call, new_atom, serialize};
|
||||
use orchid_extension::std_reqs::{ReadLimit, ReadReq, RunCommand};
|
||||
use orchid_extension::{Atomic, Expr, ForeignAtom, OwnedAtom, OwnedVariant, Supports, ToExpr};
|
||||
use orchid_extension::std_reqs::{CloseReq, FlushReq, ReadLimit, ReadReq, StartCommand, WriteReq};
|
||||
use orchid_extension::{
|
||||
Atomic, Expr, ForeignAtom, MethodSetBuilder, OwnedAtom, OwnedVariant, Supports, ToExpr,
|
||||
};
|
||||
|
||||
use crate::std::binary::binary_atom::BlobAtom;
|
||||
use crate::std::string::str_atom::StrAtom;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ReadStreamCmd {
|
||||
@@ -16,40 +19,99 @@ pub struct ReadStreamCmd {
|
||||
pub limit: ReadLimit,
|
||||
pub succ: Expr,
|
||||
pub fail: Expr,
|
||||
pub as_str: bool,
|
||||
}
|
||||
impl Atomic for ReadStreamCmd {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = ();
|
||||
fn reg_methods() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<StartCommand>() }
|
||||
}
|
||||
impl OwnedAtom for ReadStreamCmd {
|
||||
type Refs = Never;
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
}
|
||||
impl Supports<RunCommand> for ReadStreamCmd {
|
||||
async fn handle<'a>(
|
||||
&self,
|
||||
hand: Box<dyn orchid_base::ReqHandle<'a> + '_>,
|
||||
req: RunCommand,
|
||||
) -> io::Result<orchid_base::Receipt<'a>> {
|
||||
let ret = match self.hand.call(ReadReq { limit: self.limit.clone() }).await {
|
||||
None => Err(mk_errv(
|
||||
is("Atom is not readable").await,
|
||||
format!("Expected a readable stream handle, found {}", fmt(&self.hand).await),
|
||||
[self.hand.pos()],
|
||||
impl Supports<StartCommand> for ReadStreamCmd {
|
||||
async fn handle(&self, hand: Box<dyn ReqHandle>, req: StartCommand) -> io::Result<Receipt> {
|
||||
let ret = 'ret: {
|
||||
let Some(read_res) = self.hand.call(ReadReq { limit: self.limit.clone() }).await else {
|
||||
break 'ret Err(mk_errv(
|
||||
is("Atom is not readable").await,
|
||||
format!("Expected a readable stream handle, found {}", fmt(&self.hand).await),
|
||||
[self.hand.pos()],
|
||||
));
|
||||
};
|
||||
let res = match read_res {
|
||||
Err(e) => Err(mk_errv(
|
||||
is(e.kind.message()).await,
|
||||
format!("An error occurred while reading: {}", e.message),
|
||||
[self.hand.pos(), self.succ.pos().await],
|
||||
)),
|
||||
Ok(v) if !self.as_str => Ok(new_atom(BlobAtom(Rc::new(v)))),
|
||||
Ok(v) => match String::from_utf8(v) {
|
||||
Ok(s) => Ok(new_atom(StrAtom(Rc::new(s)))),
|
||||
Err(e) => Err(mk_errv(is("Invalid utf8 in input string").await, e.to_string(), [
|
||||
self.hand.pos(),
|
||||
self.succ.pos().await,
|
||||
])),
|
||||
},
|
||||
};
|
||||
Ok(match res {
|
||||
Err(e) => call(self.fail.clone(), bot(e)),
|
||||
Ok(gex) => call(self.succ.clone(), gex),
|
||||
})
|
||||
};
|
||||
hand.reply(&req, Some(serialize(ret.to_gen().await).await)).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum WriteAction {
|
||||
Write(Rc<Vec<u8>>),
|
||||
Flush,
|
||||
Close,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WriteStreamCmd {
|
||||
pub hand: ForeignAtom,
|
||||
pub action: WriteAction,
|
||||
pub succ: Expr,
|
||||
pub fail: Expr,
|
||||
}
|
||||
impl Atomic for WriteStreamCmd {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = ();
|
||||
fn reg_methods() -> MethodSetBuilder<Self> { MethodSetBuilder::new().handle::<StartCommand>() }
|
||||
}
|
||||
impl OwnedAtom for WriteStreamCmd {
|
||||
type Refs = Never;
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
}
|
||||
impl Supports<StartCommand> for WriteStreamCmd {
|
||||
async fn handle(&self, hand: Box<dyn ReqHandle>, req: StartCommand) -> io::Result<Receipt> {
|
||||
let result = match &self.action {
|
||||
WriteAction::Write(bin) => self.hand.call(WriteReq { data: bin.to_vec() }).await,
|
||||
WriteAction::Flush => self.hand.call(FlushReq).await,
|
||||
WriteAction::Close => self.hand.call(CloseReq).await,
|
||||
};
|
||||
let cont = match result {
|
||||
None => bot(mk_errv(
|
||||
is("Not a writer").await,
|
||||
format!("{} cannot be written to", fmt(&self.hand).await),
|
||||
[self.hand.pos(), self.succ.pos().await],
|
||||
)),
|
||||
Some(Err(e)) => Ok(
|
||||
Some(Err(e)) =>
|
||||
call(
|
||||
self.fail.clone(),
|
||||
bot(mk_errv(
|
||||
is(e.kind.message()).await,
|
||||
format!("An error occurred while reading: {}", e.message),
|
||||
format!("An error occurred while writing: {}", e.message),
|
||||
[self.hand.pos(), self.succ.pos().await],
|
||||
)),
|
||||
)
|
||||
.await,
|
||||
),
|
||||
Some(Ok(v)) => Ok(call(self.succ.clone(), new_atom(BlobAtom(Rc::new(v)))).await),
|
||||
Some(Ok(())) => self.succ.clone().to_gen().await,
|
||||
};
|
||||
hand.reply(&req, &Some(serialize(ret.to_gen().await).await)).await
|
||||
hand.reply(&req, Some(serialize(cont.to_gen().await).await)).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
use std::num::NonZero;
|
||||
use std::rc::Rc;
|
||||
|
||||
use itertools::Itertools;
|
||||
use orchid_base::{is, mk_errv};
|
||||
use orchid_extension::gen_expr::{call, new_atom};
|
||||
use orchid_extension::std_reqs::ReadLimit;
|
||||
use orchid_extension::tree::{GenMember, comments, fun, prefix};
|
||||
use orchid_extension::{Expr, ForeignAtom, get_arg};
|
||||
use orchid_extension::{Expr, ForeignAtom, TAtom, get_arg};
|
||||
|
||||
use crate::Int;
|
||||
use crate::std::binary::binary_atom::BlobAtom;
|
||||
use crate::std::stream::stream_cmds::ReadStreamCmd;
|
||||
use crate::std::stream::stream_cmds::{ReadStreamCmd, WriteAction, WriteStreamCmd};
|
||||
use crate::{Int, OrcString};
|
||||
|
||||
pub fn gen_stream_lib() -> Vec<GenMember> {
|
||||
prefix("std", [comments(
|
||||
["Read from and write to byte streams"],
|
||||
prefix("stream", [
|
||||
fun(true, "read_bin", async |hand: ForeignAtom, succ: Expr, fail: Expr| {
|
||||
new_atom(ReadStreamCmd { hand, succ, fail, limit: ReadLimit::End })
|
||||
new_atom(ReadStreamCmd { hand, succ, fail, as_str: false, limit: ReadLimit::End })
|
||||
}),
|
||||
fun(true, "read_str", async |hand: ForeignAtom, succ: Expr, fail: Expr| {
|
||||
new_atom(ReadStreamCmd { hand, succ, fail, as_str: true, limit: ReadLimit::End })
|
||||
}),
|
||||
fun(true, "read_until", async |hand: ForeignAtom, delim: Int, succ: Expr, fail: Expr| {
|
||||
let Ok(end) = delim.0.try_into() else {
|
||||
@@ -29,12 +33,15 @@ pub fn gen_stream_lib() -> Vec<GenMember> {
|
||||
[get_arg(1).pos().await],
|
||||
));
|
||||
};
|
||||
Ok(new_atom(ReadStreamCmd { hand, succ, fail, limit: ReadLimit::Delimiter(end) }))
|
||||
let limit = ReadLimit::Delimiter(end);
|
||||
Ok(new_atom(ReadStreamCmd { hand, succ, fail, as_str: false, limit }))
|
||||
}),
|
||||
fun(true, "read_bytes", async |hand: ForeignAtom, count: Int, succ: Expr, fail: Expr| {
|
||||
match count.0.try_into().map(NonZero::new) {
|
||||
Ok(Some(nzlen)) =>
|
||||
Ok(new_atom(ReadStreamCmd { hand, succ, fail, limit: ReadLimit::Length(nzlen) })),
|
||||
Ok(Some(nzlen)) => {
|
||||
let limit = ReadLimit::Length(nzlen);
|
||||
Ok(new_atom(ReadStreamCmd { hand, succ, fail, as_str: false, limit }))
|
||||
},
|
||||
Ok(None) => Ok(call(succ, new_atom(BlobAtom(Rc::default()))).await),
|
||||
Err(_) => Err(mk_errv(
|
||||
is("Length cannot be negative").await,
|
||||
@@ -43,6 +50,28 @@ pub fn gen_stream_lib() -> Vec<GenMember> {
|
||||
)),
|
||||
}
|
||||
}),
|
||||
fun(true, "read_line", async |hand: ForeignAtom, succ: Expr, fail: Expr| {
|
||||
const LIMIT_BR: ReadLimit = ReadLimit::Delimiter(b'\n');
|
||||
new_atom(ReadStreamCmd { hand, succ, fail, as_str: true, limit: LIMIT_BR })
|
||||
}),
|
||||
fun(true, "write_str", async |hand: ForeignAtom, str: OrcString, succ: Expr, fail: Expr| {
|
||||
let action = WriteAction::Write(Rc::new(str.get_string().await.bytes().collect_vec()));
|
||||
new_atom(WriteStreamCmd { hand, action, succ, fail })
|
||||
}),
|
||||
fun(
|
||||
true,
|
||||
"write_bin",
|
||||
async |hand: ForeignAtom, bin: TAtom<BlobAtom>, succ: Expr, fail: Expr| {
|
||||
let action = WriteAction::Write(bin.own().await.0.clone());
|
||||
new_atom(WriteStreamCmd { hand, action, succ, fail })
|
||||
},
|
||||
),
|
||||
fun(true, "flush", async |hand: ForeignAtom, succ: Expr, fail: Expr| {
|
||||
new_atom(WriteStreamCmd { hand, action: WriteAction::Flush, succ, fail })
|
||||
}),
|
||||
fun(true, "close", async |hand: ForeignAtom, succ: Expr, fail: Expr| {
|
||||
new_atom(WriteStreamCmd { hand, action: WriteAction::Close, succ, fail })
|
||||
}),
|
||||
]),
|
||||
)])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user