use core::fmt::Debug;
use ::toad_msg::{Id, OptNumber, OptValue, OptionMap, Token, TryIntoBytes};
use embedded_time::Instant;
use naan::prelude::MonadOnce;
use no_std_net::SocketAddr;
#[cfg(feature = "alloc")]
use std_alloc::vec::Vec;
use toad_array::{AppendCopy, Array};
use crate::config::Config;
use crate::net::{Addrd, Socket};
use crate::req::Req;
use crate::resp::Resp;
use crate::step::Step;
use crate::time::Clock;
use crate::todo::String;
#[derive(Debug)]
#[allow(missing_docs)]
pub enum Error<Step, Socket> {
MessageToBytes(::toad_msg::to_bytes::MessageToBytesError),
Step(Step),
Socket(Socket),
Clock(embedded_time::clock::Error),
}
impl<Step, Socket> PlatformError<Step, Socket> for Error<Step, Socket>
where Step: core::fmt::Debug,
Socket: core::fmt::Debug
{
fn msg_to_bytes(e: ::toad_msg::to_bytes::MessageToBytesError) -> Self {
Self::MessageToBytes(e)
}
fn step(e: Step) -> Self {
Self::Step(e)
}
fn socket(e: Socket) -> Self {
Self::Socket(e)
}
fn clock(e: embedded_time::clock::Error) -> Self {
Self::Clock(e)
}
}
pub trait PlatformError<StepError, SocketError>: Sized + core::fmt::Debug {
fn msg_to_bytes(e: ::toad_msg::to_bytes::MessageToBytesError) -> Self;
fn step(e: StepError) -> Self;
fn socket(e: SocketError) -> Self;
fn clock(e: embedded_time::clock::Error) -> Self;
}
pub trait Platform<Steps>
where Steps:
Step<Self::Types, PollReq = Addrd<Req<Self::Types>>, PollResp = Addrd<Resp<Self::Types>>>
{
type Types: PlatformTypes;
type Error: PlatformError<<Steps as Step<Self::Types>>::Error,
<<Self::Types as PlatformTypes>::Socket as Socket>::Error>;
fn snapshot(&self) -> Result<Snapshot<Self::Types>, Self::Error> {
use embedded_time::Clock;
self.socket()
.poll()
.map_err(Self::Error::socket)
.and_then(|recvd_dgram| {
self.clock()
.try_now()
.map_err(Self::Error::clock)
.map(|time| Snapshot { recvd_dgram,
config: self.config(),
time })
})
}
fn poll_req(&self) -> nb::Result<Addrd<Req<Self::Types>>, Self::Error> {
let mut effects = <Self::Types as PlatformTypes>::Effects::default();
let res = self.snapshot()
.map_err(nb::Error::Other)
.and_then(|snapshot| {
self.steps()
.poll_req(&snapshot, &mut effects)
.unwrap_or(Err(nb::Error::WouldBlock))
.map_err(|e: nb::Error<_>| e.map(Self::Error::step))
});
self.exec_many(effects)
.map_err(|(_, e)| e)
.map_err(nb::Error::Other)?;
res
}
fn notify<P>(&self, path: P) -> Result<(), Self::Error>
where P: AsRef<str> + Clone
{
let mut effects = <Self::Types as PlatformTypes>::Effects::default();
self.steps()
.notify(path, &mut effects)
.map_err(Self::Error::step)?;
self.exec_many(effects).map_err(|(_, e)| e)
}
fn poll_resp(&self,
token: Token,
addr: SocketAddr)
-> nb::Result<Addrd<Resp<Self::Types>>, Self::Error> {
let mut effects = <Self::Types as PlatformTypes>::Effects::default();
let res = self.snapshot()
.map_err(nb::Error::Other)
.and_then(|snapshot| {
self.steps()
.poll_resp(&snapshot, &mut effects, token, addr)
.unwrap_or(Err(nb::Error::WouldBlock))
.map_err(|e: nb::Error<_>| e.map(Self::Error::step))
});
self.exec_many(effects)
.map_err(|(_, e)| e)
.map_err(nb::Error::Other)?;
res
}
fn log(&self, level: log::Level, msg: String<1000>) -> Result<(), Self::Error>;
fn send_msg(&self,
mut addrd_msg: Addrd<self::toad_msg::Message<Self::Types>>)
-> nb::Result<(Id, Token), Self::Error> {
type Dgram<P> = <<P as PlatformTypes>::Socket as Socket>::Dgram;
let mut effs = <Self::Types as PlatformTypes>::Effects::default();
let mut on_message_sent_effs = <Self::Types as PlatformTypes>::Effects::default();
self.snapshot()
.discard(|snapshot: &Snapshot<Self::Types>| {
self.steps()
.before_message_sent(snapshot, &mut effs, &mut addrd_msg)
.map_err(Self::Error::step)
})
.discard(|_: &Snapshot<Self::Types>| self.exec_many(effs).map_err(|(_, e)| e))
.and_then(|snapshot| {
addrd_msg.clone().fold(|msg, addr| {
let (id, token) = (msg.id, msg.token);
msg.try_into_bytes::<Dgram<Self::Types>>()
.map_err(Self::Error::msg_to_bytes)
.map(|bytes| (id, token, snapshot, Addrd(bytes, addr)))
})
})
.map_err(nb::Error::Other)
.discard(|(_, _, _, addrd_bytes): &(_, _, _, Addrd<<<Self::Types as PlatformTypes>::Socket as Socket>::Dgram>)| {
self.socket()
.send(addrd_bytes.as_ref().map(|s| s.as_ref()))
.map_err(|e: nb::Error<_>| e.map(Self::Error::socket))
})
.discard(|(_, _, snapshot, _): &(_, _, Snapshot<<Self as Platform<Steps>>::Types>, _)| {
self.steps()
.on_message_sent(snapshot, &mut on_message_sent_effs, &addrd_msg)
.map_err(Self::Error::step)
.map_err(nb::Error::Other)
})
.discard(|_: &(_, _, _, _)| self.exec_many(on_message_sent_effs).map_err(|(_, e)| e).map_err(nb::Error::Other))
.map(|(id, token, _, _)| (id, token))
}
fn exec_1(&self, effect: &Effect<Self::Types>) -> nb::Result<(), Self::Error> {
match effect {
| &Effect::Log(level, msg) => self.log(level, msg).map_err(nb::Error::Other),
| &Effect::Send(ref msg) => self.send_msg(msg.clone()).map(|_| ()),
| &Effect::Nop => Ok(()),
}
}
fn exec_many(&self,
effects: <Self::Types as PlatformTypes>::Effects)
-> Result<(), (<Self::Types as PlatformTypes>::Effects, Self::Error)> {
effects.into_iter()
.fold(Ok(()), |so_far, eff| match so_far {
| Ok(()) => nb::block!(self.exec_1(&eff)).map_err(|e| {
let mut effs: <Self::Types as PlatformTypes>::Effects =
Default::default();
effs.push(eff);
(effs, e)
}),
| Err((mut effs, e)) => {
effs.push(eff);
Err((effs, e))
},
})
}
fn config(&self) -> Config;
fn steps(&self) -> &Steps;
fn socket(&self) -> &<Self::Types as PlatformTypes>::Socket;
fn clock(&self) -> &<Self::Types as PlatformTypes>::Clock;
}
pub trait PlatformTypes: Sized + 'static + core::fmt::Debug {
type MessagePayload: Array<Item = u8> + Clone + Debug + PartialEq + AppendCopy<u8>;
type MessageOptionBytes: Array<Item = u8> + 'static + Clone + Debug + PartialEq + AppendCopy<u8>;
type MessageOptionMapOptionValues: Array<Item = OptValue<Self::MessageOptionBytes>>
+ Clone
+ PartialEq
+ Debug;
type MessageOptions: OptionMap<OptValues = Self::MessageOptionMapOptionValues, OptValue = Self::MessageOptionBytes>
+ Clone
+ Debug
+ PartialEq;
type Clock: Clock;
type Socket: Socket;
type Effects: Array<Item = Effect<Self>> + core::fmt::Debug;
}
#[allow(missing_debug_implementations)]
#[non_exhaustive]
pub struct Snapshot<P: PlatformTypes> {
pub time: Instant<P::Clock>,
pub recvd_dgram: Option<Addrd<<P::Socket as Socket>::Dgram>>,
pub config: Config,
}
impl<P: PlatformTypes> core::fmt::Debug for Snapshot<P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Snapshot")
.field("time", &self.time)
.field("recvd_dgram", &self.recvd_dgram)
.field("config", &self.config)
.finish()
}
}
impl<P: PlatformTypes> Clone for Snapshot<P> {
fn clone(&self) -> Self {
Self { time: self.time,
recvd_dgram: self.recvd_dgram.clone(),
config: self.config }
}
}
#[allow(missing_docs)]
pub enum Effect<P>
where P: PlatformTypes
{
Send(Addrd<self::toad_msg::Message<P>>),
Log(log::Level, String<1000>),
Nop,
}
impl<P> Default for Effect<P> where P: PlatformTypes
{
fn default() -> Self {
Self::Nop
}
}
impl<P: PlatformTypes> Clone for Effect<P> {
fn clone(&self) -> Self {
match self {
| Effect::Send(m) => Effect::Send(m.clone()),
| Effect::Log(l, m) => Effect::Log(*l, *m),
| Effect::Nop => Effect::Nop,
}
}
}
impl<P: PlatformTypes> core::fmt::Debug for Effect<P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
| Self::Send(m) => f.debug_tuple("Send").field(m).finish(),
| Self::Log(l, s) => f.debug_tuple("Log").field(l).field(s).finish(),
| Self::Nop => f.debug_tuple("Nop").finish(),
}
}
}
impl<P: PlatformTypes> PartialEq for Effect<P> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
| (Self::Send(a), Self::Send(b)) => a == b,
| (Self::Log(al, am), Self::Log(bl, bm)) => al == bl && am == bm,
| _ => false,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Retryable<P: PlatformTypes, T>(pub T, pub crate::retry::RetryTimer<P::Clock>);
impl<P: PlatformTypes, T> Retryable<P, T> {
pub fn unwrap(self) -> T {
self.0
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[derive(Copy)]
pub struct Alloc<Clk, Sock>(core::marker::PhantomData<(Clk, Sock)>)
where Clk: Clock + 'static,
Sock: Socket + 'static;
#[cfg(feature = "alloc")]
impl<Clk: Clock + 'static, Sock: Socket + 'static> core::fmt::Debug for Alloc<Clk, Sock> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Alloc::<_, _>")
}
}
#[cfg(feature = "alloc")]
impl<Clk: Clock + 'static, Sock: Socket + 'static> Clone for Alloc<Clk, Sock> {
fn clone(&self) -> Self {
Self(Default::default())
}
}
#[cfg(feature = "alloc")]
impl<Clk: Clock + Debug + 'static, Sock: Socket + 'static> PlatformTypes for Alloc<Clk, Sock> {
type MessagePayload = Vec<u8>;
type MessageOptionBytes = Vec<u8>;
type MessageOptionMapOptionValues = Vec<OptValue<Vec<u8>>>;
type MessageOptions = std_alloc::collections::BTreeMap<OptNumber, Vec<OptValue<Vec<u8>>>>;
type Clock = Clk;
type Socket = Sock;
type Effects = Vec<Effect<Self>>;
}
#[deprecated = "use `toad::platform::toad_msg::Message`"]
pub use self::toad_msg::Message;
#[allow(missing_docs)]
pub mod toad_msg {
use super::*;
pub type Message<P> = ::toad_msg::Message<Payload<P>, opt::Map<P>>;
pub type Payload<P> = <P as PlatformTypes>::MessagePayload;
pub mod opt {
use super::*;
pub type Map<P> = <P as PlatformTypes>::MessageOptions;
pub type Opt<P> = ::toad_msg::Opt<Bytes<P>>;
pub type Bytes<P> = <Map<P> as ::toad_msg::OptionMap>::OptValue;
pub type OptValue<P> = ::toad_msg::OptValue<Bytes<P>>;
pub type SetError<P> =
::toad_msg::SetOptionError<::toad_msg::OptValue<Bytes<P>>, <Map<P> as OptionMap>::OptValues>;
}
}