pub struct Ap<S, P, T, E>(_)
where
S: ApState,
P: PlatformTypes;
Expand description
Server Resources & Request-Response Semantics
Ap
can be thought of as an extension of Result
that adds new, servery, states.
Variants
Ok
,Err
-Result::Ok
,Result::Err
OkHydrated
- this isResult::Ok
with a CoAP request and partially consumed request pathReject
,RejectHydrated
- this has been rejected by the endpoint because a filter failed. This behaves just likeErr
but is separate because it should always be recovered. The unhydrated variant (constructed withAp::reject()
is useful for writing helper functions that exist outside of a specific server context)Respond
,RespondHydrated
- this request has been matched with a resource and has a response to send. This implies no other endpoints or resources will see the original request.
States
Unhydrated
-Ap
that is just some data; is not a result that the server can act onHydrated
-Ap
that is just some data in the context of an incoming request; is not a result that the server can act onCompleteWhenHydrated
-Ap
that is a result that the server can act on once it is lifted to the context of a requestComplete
-Ap
that is a result that the server can act on. This is the final stateAp
s should always reach
Type parameters
S: ApState
- compile-time state that guarantees users complete an Ap by rejecting, responding, or erroring.P: PlatformTypes
- DecouplesAp
from the platform being run on (e.g. heap allocation)T
- The type in the “Ok” channelE
- The type in the “Err” channel
Constructing an Ap
Ap::ok
(Unhydrated
)Ap::ok_hydrated
(Hydrated
)Ap::reject
(CompleteWhenHydrated
)Ap::respond
(CompleteWhenHydrated
)Ap::err
(Complete
)Ap::reject_hydrated
(Complete
)Ap::respond_hydrated
(Complete
)
Destructuring an Ap
Modifying & combining Ap
s
Changing the value (or type) in the Ok channel
This can be done with Ap::map
.
use toad::server::ap::*;
use toad::std::{dtls, PlatformTypes as Std};
let my_ap: Ap<_, Std<dtls::Y>, String, ()> = Ap::ok(1234u32).map(|n| n.to_string());
assert_eq!(my_ap, Ap::ok("1234".into()));
Changing the value (or type) in the Err channel
This can be done with Ap::map_err
.
use toad::server::ap::*;
use toad::std::{dtls, PlatformTypes as Std};
#[derive(Debug)]
enum Error {
UhOh(String),
}
let my_ap: Ap<_, Std<dtls::Y>, (), String> =
Ap::err(Error::UhOh("failed to do the thing!".to_string())).map_err(|e| format!("{e:?}"));
assert_eq!(my_ap,
Ap::err("UhOh(\"failed to do the thing!\")".to_string()));
Combining multiple Aps
Ap::bind
is used to combine Aps. In practice, bind is identical to Result::and_then
.
The provided closure will be called when the Ap
is in the Ok
or OkHydrated
channels,
and ignored when the Ap
is any other state.
Hydration is contagious; if the closure returns an unhydrated variant (Ap::reject
, Ap::respond
, Ap::ok
),
and self
is Ap::ok_hydrated
then the closure’s return value will be hydrated before
continuing.
(e.g. self is ok_hydrated
, closure returned reject
, output will be reject_hydrated
)
use toad::net::Addrd;
use toad::req::Req;
use toad::server::ap::*;
use toad::std::{dtls, PlatformTypes as Std};
#[derive(Debug, PartialEq)]
enum Error {
UhOh(String),
}
let addr: no_std_net::SocketAddr = "1.1.1.1:5683".parse().unwrap();
let req = || Req::get("hello");
// OkHydrated.bind(Ok) => OkHydrated
let ok_hy_123: Ap<_, Std<dtls::Y>, u32, Error> =
Ap::ok_hydrated(123, Hydrate::from_request(Addrd(req(), addr)));
let ok_hy_234 = ok_hy_123.bind(|n| Ap::ok(n + 111));
assert_eq!(ok_hy_234,
Ap::ok_hydrated(234, Hydrate::from_request(Addrd(req(), addr))));
// OkHydrated.bind(Err) => Err
let ok_hy: Ap<_, Std<dtls::Y>, u32, Error> =
Ap::ok_hydrated(123, Hydrate::from_request(Addrd(req(), addr)));
let err: Ap<_, _, u32, Error> = ok_hy.bind(|n| Ap::err(Error::UhOh("".into())));
assert_eq!(err, Ap::err(Error::UhOh("".into())));
// RejectHydrated.bind(Err) => RejectHydrated
let reject: Ap<_, Std<dtls::Y>, u32, Error> = Ap::reject_hydrated(Addrd(req(), addr));
let reject_unchanged: Ap<_, _, u32, Error> = reject.bind(|n| Ap::err(Error::UhOh("".into())));
assert_eq!(reject_unchanged, Ap::reject_hydrated(Addrd(req(), addr)));
Implementations§
source§impl<P, T, E> Ap<Unhydrated, P, T, E>where
P: PlatformTypes,
E: Debug,
impl<P, T, E> Ap<Unhydrated, P, T, E>where P: PlatformTypes, E: Debug,
sourcepub fn from_result(res: Result<T, E>) -> Self
pub fn from_result(res: Result<T, E>) -> Self
Map Result::Ok
-> Ap::ok
, Result::Err
-> Ap::err
source§impl<P, T, Error> Ap<CompleteWhenHydrated, P, T, Error>where
P: PlatformTypes,
Error: Debug,
impl<P, T, Error> Ap<CompleteWhenHydrated, P, T, Error>where P: PlatformTypes, Error: Debug,
source§impl<T, P, E> Ap<Hydrated, P, T, E>where
P: PlatformTypes,
E: Debug,
impl<T, P, E> Ap<Hydrated, P, T, E>where P: PlatformTypes, E: Debug,
sourcepub fn bind_hydrated<F, S2, B>(
self,
f: F
) -> Ap<<Hydrated as Combine<S2>>::Out, P, B, E>where
F: FnOnce(T, &Addrd<Req<P>>) -> Ap<S2, P, B, E>,
S2: ApState,
Hydrated: Combine<S2>,
pub fn bind_hydrated<F, S2, B>( self, f: F ) -> Ap<<Hydrated as Combine<S2>>::Out, P, B, E>where F: FnOnce(T, &Addrd<Req<P>>) -> Ap<S2, P, B, E>, S2: ApState, Hydrated: Combine<S2>,
Use a function F
(T -> Ap<B, E>
) to transform the data contained in Ap
and combine the result with self.
The function will only be called if this is Ap::ok
or Ap::ok_hydrated
.
sourcepub fn ok_hydrated(t: T, hy: Hydrate<P>) -> Ap<Hydrated, P, T, E>
pub fn ok_hydrated(t: T, hy: Hydrate<P>) -> Ap<Hydrated, P, T, E>
sourcepub fn respond_hydrated(req: Addrd<Req<P>>, rep: Respond<P>) -> Self
pub fn respond_hydrated(req: Addrd<Req<P>>, rep: Respond<P>) -> Self
Ap::respond
with a request context
source§impl<P, T, E> Ap<Complete, P, T, E>where
P: PlatformTypes,
E: Debug,
impl<P, T, E> Ap<Complete, P, T, E>where P: PlatformTypes, E: Debug,
sourcepub fn pretend<S>(self) -> Ap<S, P, T, E>where
S: ApState,
pub fn pretend<S>(self) -> Ap<S, P, T, E>where S: ApState,
Coerce the state type to any other (this only applies to Ap
s which are known to be Complete
.)
sourcepub fn reject_hydrated(req: Addrd<Req<P>>) -> Self
pub fn reject_hydrated(req: Addrd<Req<P>>) -> Self
Ap::reject
with a request context
source§impl<S, P, T, E> Ap<S, P, T, E>where
P: PlatformTypes,
S: ApState,
E: Debug,
impl<S, P, T, E> Ap<S, P, T, E>where P: PlatformTypes, S: ApState, E: Debug,
sourcepub fn is_ok(&self) -> bool
pub fn is_ok(&self) -> bool
Is this Ap::ok
or Ap::ok_hydrated
?
sourcepub fn is_rejected(&self) -> bool
pub fn is_rejected(&self) -> bool
Is this Ap::reject
or Ap::reject_hydrated
?
sourcepub fn hydrate(
self,
req: Addrd<Req<P>>
) -> Ap<<S as Combine<Hydrated>>::Out, P, T, E>
pub fn hydrate( self, req: Addrd<Req<P>> ) -> Ap<<S as Combine<Hydrated>>::Out, P, T, E>
Convert Ap::ok
-> Ap::ok_hydrated
, Ap::reject
-> Ap::reject_hydrated
,
Ap::respond
-> Ap::respond_hydrated
.
sourcepub fn pretend_unhydrated(self) -> Ap<Unhydrated, P, T, E>
pub fn pretend_unhydrated(self) -> Ap<Unhydrated, P, T, E>
More extreme than Ap::pretend_hydrated
, this will accept
an Ap
of any ApState
and fix it as Unhydrated
.
sourcepub fn try_unwrap_respond(self) -> Result<Respond<P>, Self>
pub fn try_unwrap_respond(self) -> Result<Respond<P>, Self>
If this is Ap::respond
or Ap::respond_hydrated
, unwrap and yield the data
contained in it in Result::Ok
.
If not, return Err(self)
.
sourcepub fn try_unwrap_err(self) -> Result<E, Self>
pub fn try_unwrap_err(self) -> Result<E, Self>
If this is Ap::err
, unwrap and yield the error
contained in it in Result::Ok
.
If not, return Err(self)
.
sourcepub fn try_unwrap_ok(self) -> Result<T, Self>
pub fn try_unwrap_ok(self) -> Result<T, Self>
If this is Ap::ok
or Ap::ok_hydrated
,
unwrap and yield the data contained in it
and return Result::Ok
.
If not, return Err(self)
.
sourcepub fn try_unwrap_ok_hydrated(self) -> Result<(T, Hydrate<P>), Self>
pub fn try_unwrap_ok_hydrated(self) -> Result<(T, Hydrate<P>), Self>
If this is Ap::ok_hydrated
,
unwrap and yield the data contained in it
and return Result::Ok
.
If not, return Err(self)
.
sourcepub fn pipe<F, R>(self, f: F) -> Rwhere
F: FnOnce(Self) -> R,
pub fn pipe<F, R>(self, f: F) -> Rwhere F: FnOnce(Self) -> R,
Apply a function that accepts Self
to self
.
use toad::server::ap::*;
use toad::std::{dtls, PlatformTypes as Std};
fn ok_to_err<S: state::ApState>(ap: Ap<S, Std<dtls::Y>, (), ()>) -> Ap<S, Std<dtls::Y>, (), ()> {
if ap.is_ok() {
Ap::err(()).pretend()
} else {
panic!("must be ok")
}
}
let ap = || Ap::<_, Std<dtls::Y>, (), ()>::ok(());
// with pipe:
ap().pipe(ok_to_err);
// without:
ok_to_err(ap());
sourcepub fn etag(self, etag: P::MessageOptionBytes) -> Self
pub fn etag(self, etag: P::MessageOptionBytes) -> Self
If this is Ap::respond
or Ap::respond_hydrated
,
set the etag
option for the response before sending.
sourcepub fn map<F, B>(self, f: F) -> Ap<S, P, B, E>where
F: FnOnce(T) -> B,
pub fn map<F, B>(self, f: F) -> Ap<S, P, B, E>where F: FnOnce(T) -> B,
Use a function F
(T -> B
) to transform the data contained in Ap
.
The function will only be called if this is Ap::ok
or Ap::ok_hydrated
.
sourcepub fn map_err<F, B>(self, f: F) -> Ap<S, P, T, B>where
F: FnOnce(E) -> B,
pub fn map_err<F, B>(self, f: F) -> Ap<S, P, T, B>where F: FnOnce(E) -> B,
Use a function F
(E -> B
) to transform the error contained in Ap
.
The function will only be called if this is Ap::err
.
sourcepub fn bind<F, S2, B>(self, f: F) -> Ap<<S as Combine<S2>>::Out, P, B, E>where
F: FnOnce(T) -> Ap<S2, P, B, E>,
S2: ApState,
S: Combine<S2>,
pub fn bind<F, S2, B>(self, f: F) -> Ap<<S as Combine<S2>>::Out, P, B, E>where F: FnOnce(T) -> Ap<S2, P, B, E>, S2: ApState, S: Combine<S2>,
Use a function F
(T -> Ap<B, E>
) to transform the data contained in Ap
and combine the result with self.
The function will only be called if this is Ap::ok
or Ap::ok_hydrated
.
sourcepub fn bind_discard<S2, F>(self, f: F) -> Selfwhere
F: for<'a> FnOnce(&'a T) -> Ap<S2, P, (), E>,
S2: ApState,
S: Combine<S2>,
pub fn bind_discard<S2, F>(self, f: F) -> Selfwhere F: for<'a> FnOnce(&'a T) -> Ap<S2, P, (), E>, S2: ApState, S: Combine<S2>,
Shorthand for bind
ing an Ap of unit Ap<_, _, (), E>
and keeping the T
.
fn do_stuff(t: &T) -> Ap<_, _, (), E> { ... }
ap.bind(|t| do_stuff(&t).map(|_| t))
ap.bind_discard(do_stuff)
sourcepub fn reject_on_err<E2>(self) -> Ap<Unhydrated, P, T, E2>
pub fn reject_on_err<E2>(self) -> Ap<Unhydrated, P, T, E2>
Silently ignore errors, mapping to Ap::reject
.
Trait Implementations§
source§impl<S, P, T, E> Clone for Ap<S, P, T, E>where
S: ApState,
P: PlatformTypes,
E: Clone,
T: Clone,
impl<S, P, T, E> Clone for Ap<S, P, T, E>where S: ApState, P: PlatformTypes, E: Clone, T: Clone,
source§impl<S, P, T, E> Debug for Ap<S, P, T, E>where
S: ApState,
P: PlatformTypes,
E: Debug,
T: Debug,
impl<S, P, T, E> Debug for Ap<S, P, T, E>where S: ApState, P: PlatformTypes, E: Debug, T: Debug,
Auto Trait Implementations§
impl<S, P, T, E> RefUnwindSafe for Ap<S, P, T, E>where E: RefUnwindSafe, S: RefUnwindSafe, T: RefUnwindSafe, <P as PlatformTypes>::MessageOptionBytes: RefUnwindSafe, <P as PlatformTypes>::MessageOptionMapOptionValues: RefUnwindSafe, <P as PlatformTypes>::MessageOptions: RefUnwindSafe, <P as PlatformTypes>::MessagePayload: RefUnwindSafe,
impl<S, P, T, E> Send for Ap<S, P, T, E>where E: Send, S: Send, T: Send, <P as PlatformTypes>::MessageOptionBytes: Send, <P as PlatformTypes>::MessageOptionMapOptionValues: Send, <P as PlatformTypes>::MessageOptions: Send, <P as PlatformTypes>::MessagePayload: Send,
impl<S, P, T, E> Sync for Ap<S, P, T, E>where E: Sync, S: Sync, T: Sync, <P as PlatformTypes>::MessageOptionBytes: Sync, <P as PlatformTypes>::MessageOptionMapOptionValues: Sync, <P as PlatformTypes>::MessageOptions: Sync, <P as PlatformTypes>::MessagePayload: Sync,
impl<S, P, T, E> Unpin for Ap<S, P, T, E>where E: Unpin, S: Unpin, T: Unpin, <P as PlatformTypes>::MessageOptionBytes: Unpin, <P as PlatformTypes>::MessageOptionMapOptionValues: Unpin, <P as PlatformTypes>::MessageOptions: Unpin, <P as PlatformTypes>::MessagePayload: Unpin,
impl<S, P, T, E> UnwindSafe for Ap<S, P, T, E>where E: UnwindSafe, S: UnwindSafe, T: UnwindSafe, <P as PlatformTypes>::MessageOptionBytes: UnwindSafe, <P as PlatformTypes>::MessageOptionMapOptionValues: UnwindSafe, <P as PlatformTypes>::MessageOptions: UnwindSafe, <P as PlatformTypes>::MessagePayload: UnwindSafe,
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<F, A, TF, T> Sequence<F, A, TF> for T
impl<F, A, TF, T> Sequence<F, A, TF> for T
source§fn sequence<Ap>(self) -> <Ap as HKT1>::T<<F as HKT1>::T<A>>where
Self: Sized + Traversable<F, <Ap as HKT1>::T<A>, A, TF> + Foldable<F, <Ap as HKT1>::T<A>>,
Ap: HKT1,
<Ap as HKT1>::T<A>: Applicative<Ap, A> + ApplyOnce<Ap, A>,
<Ap as HKT1>::T<TF>: Applicative<Ap, TF> + ApplyOnce<Ap, TF>,
<Ap as HKT1>::T<<F as HKT1>::T<A>>: Applicative<Ap, <F as HKT1>::T<A>> + ApplyOnce<Ap, <F as HKT1>::T<A>>,
F: HKT1<T<<Ap as HKT1>::T<A>> = Self>,
fn sequence<Ap>(self) -> <Ap as HKT1>::T<<F as HKT1>::T<A>>where Self: Sized + Traversable<F, <Ap as HKT1>::T<A>, A, TF> + Foldable<F, <Ap as HKT1>::T<A>>, Ap: HKT1, <Ap as HKT1>::T<A>: Applicative<Ap, A> + ApplyOnce<Ap, A>, <Ap as HKT1>::T<TF>: Applicative<Ap, TF> + ApplyOnce<Ap, TF>, <Ap as HKT1>::T<<F as HKT1>::T<A>>: Applicative<Ap, <F as HKT1>::T<A>> + ApplyOnce<Ap, <F as HKT1>::T<A>>, F: HKT1<T<<Ap as HKT1>::T<A>> = Self>,
Sequence