use toad_array::Array;
use toad_msg::{CodeKind, Type};
use super::{exec_inner_step, Step, StepOutput};
use crate::net::Addrd;
use crate::platform::{Effect, PlatformTypes};
use crate::req::Req;
use crate::resp::Resp;
#[derive(Debug, Clone, Copy)]
pub struct Ack<S>(S);
impl<S: Default> Default for Ack<S> {
fn default() -> Self {
Ack(Default::default())
}
}
impl<S> Ack<S> {
pub fn new(s: S) -> Self {
Self(s)
}
}
type InnerPollReq<P> = Addrd<Req<P>>;
type InnerPollResp<P> = Addrd<Resp<P>>;
impl<Inner: Step<P, PollReq = InnerPollReq<P>, PollResp = InnerPollResp<P>>, P: PlatformTypes>
Step<P> for Ack<Inner>
{
type PollReq = Addrd<Req<P>>;
type PollResp = Addrd<Resp<P>>;
type Error = Inner::Error;
type Inner = Inner;
fn inner(&self) -> &Inner {
&self.0
}
fn poll_req(&self,
snap: &crate::platform::Snapshot<P>,
effects: &mut <P as PlatformTypes>::Effects)
-> StepOutput<Self::PollReq, Inner::Error> {
match exec_inner_step!(self.0.poll_req(snap, effects), core::convert::identity) {
| Some(req)
if req.data().as_ref().ty == Type::Con
&& req.data().as_ref().code.kind() == CodeKind::Request =>
{
effects.push(Effect::Send(Addrd(Resp::ack(req.as_ref().data()).into(), req.addr())));
Some(Ok(req))
},
| Some(req) => Some(Ok(req)),
| None => None,
}
}
fn poll_resp(&self,
snap: &crate::platform::Snapshot<P>,
effects: &mut <P as PlatformTypes>::Effects,
token: toad_msg::Token,
addr: no_std_net::SocketAddr)
-> StepOutput<Self::PollResp, Inner::Error> {
exec_inner_step!(self.0.poll_resp(snap, effects, token, addr),
core::convert::identity).map(Ok)
}
}
#[cfg(test)]
mod test {
use toad_msg::{Code, Type};
use super::super::test;
use super::{Ack, Effect, Step};
use crate::net::Addrd;
use crate::platform;
use crate::req::Req;
use crate::resp::Resp;
type InnerPollReq = super::InnerPollReq<crate::test::Platform>;
type InnerPollResp = super::InnerPollResp<crate::test::Platform>;
fn test_msg(ty: Type,
code: Code)
-> (Addrd<Req<crate::test::Platform>>, Addrd<Resp<crate::test::Platform>>) {
use toad_msg::*;
type Msg = platform::Message<crate::test::Platform>;
let msg = Msg { id: Id(1),
ty,
ver: Default::default(),
token: Token(Default::default()),
code,
opts: Default::default(),
payload: Payload(Default::default()) };
let addr = crate::test::dummy_addr();
(Addrd(Req::<_>::from(msg.clone()), addr), Addrd(Resp::<_>::from(msg), addr))
}
test::test_step!(
GIVEN Ack::<Dummy> where Dummy: {Step<PollReq = InnerPollReq, PollResp = InnerPollResp, Error = ()>};
WHEN inner_errors [
(inner.poll_req => { Some(Err(nb::Error::Other(()))) }),
(inner.poll_resp => { Some(Err(nb::Error::Other(()))) })
]
THEN this_should_error [
(poll_req(_, _) should satisfy { |out| assert_eq!(out, Some(Err(nb::Error::Other(())))) }),
(poll_resp(_, _, _, _) should satisfy { |out| assert_eq!(out, Some(Err(nb::Error::Other(())))) })
]
);
test::test_step!(
GIVEN Ack::<Dummy> where Dummy: {Step<PollReq = InnerPollReq, PollResp = InnerPollResp, Error = ()>};
WHEN inner_blocks [
(inner.poll_req => { Some(Err(nb::Error::WouldBlock)) }),
(inner.poll_resp => { Some(Err(nb::Error::WouldBlock)) })
]
THEN this_should_block [
(poll_req(_, _) should satisfy { |out| assert_eq!(out, Some(Err(nb::Error::WouldBlock))) }),
(poll_resp(_, _, _, _) should satisfy { |out| assert_eq!(out, Some(Err(nb::Error::WouldBlock))) })
]
);
test::test_step!(
GIVEN Ack::<Dummy> where Dummy: {Step<PollReq = InnerPollReq, PollResp = InnerPollResp, Error = ()>};
WHEN inner_yields_non_request [
(inner.poll_req => { Some(Ok(test_msg(Type::Non, Code::new(1, 01)).0)) })
]
THEN poll_req_should_noop [
(poll_req(_, _) should satisfy { |out| assert_eq!(out, Some(Ok(test_msg(Type::Non, Code::new(1, 01)).0))) }),
(effects == { vec![] })
]
);
test::test_step!(
GIVEN Ack::<Dummy> where Dummy: {Step<PollReq = InnerPollReq, PollResp = InnerPollResp, Error = ()>};
WHEN inner_yields_response [
(inner.poll_req => { Some(Ok(test_msg(Type::Ack, Code::new(0, 00)).0)) })
]
THEN poll_req_should_noop [
(poll_req(_, _) should satisfy { |out| assert_eq!(out, Some(Ok(test_msg( Type::Ack, Code::new(0, 00)).0))) }),
(effects == { vec![] })
]
);
test::test_step!(
GIVEN Ack::<Dummy> where Dummy: {Step<PollReq = InnerPollReq, PollResp = InnerPollResp, Error = ()>};
WHEN inner_yields_con_request [
(inner.poll_req => { Some(Ok(test_msg(Type::Con, Code::new(0, 01)).0)) })
]
THEN poll_req_should_ack [
(poll_req(_, _) should satisfy { |out| assert_eq!(out, Some(Ok(test_msg(Type::Con, Code::new(0, 01)).0))) }),
(effects == {
vec![
Effect::Send(
Addrd(
Resp::ack(&test_msg(Type::Con, Code::new(1, 01)).0.0)
.into(),
crate::test::dummy_addr()
)
)
]
})
]
);
test::test_step!(
GIVEN Ack::<Dummy> where Dummy: {Step<PollReq = InnerPollReq, PollResp = InnerPollResp, Error = ()>};
WHEN inner_yields_anything [
(inner.poll_resp => { Some(Ok(test_msg(Type::Ack, Code::new(2, 04)).1)) })
]
THEN poll_resp_should_noop [
(poll_resp(_, _, _, _) should satisfy { |out| assert_eq!(out, Some(Ok(test_msg(Type::Ack, Code::new(2, 04)).1))) }),
(effects == { vec![] })
]
);
}