#![no_std]
mod builder;
mod conversions;
use coap_message::{MinimalWritableMessage, ReadableMessage};
use coap_request::{Request, Stack};
use builder::Builder;
pub use conversions::AsUriPath;
pub struct Code {
code: u8,
}
pub struct WithPath<S: Stack + ?Sized, Prev: Builder<S>, P: AsUriPath> {
previous: Prev,
path: P,
_phantom: core::marker::PhantomData<S>,
}
pub struct WithRequestCallback<S: Stack + ?Sized, Prev: Builder<S>, F>
where
F: FnMut(&mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>,
{
previous: Prev,
f: F,
_phantom: core::marker::PhantomData<S>,
}
impl<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, F1>
WithRequestCallback<S, Prev, F1>
where
F1: FnMut(&mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>,
{
pub fn processing_response_payload_through<O, F2>(
self,
f: F2,
) -> ProcessingResponse<S, Self, O, F2>
where
F2: for<'a> FnOnce(&'a [u8]) -> O,
{
ProcessingResponse {
previous: self,
f: Some(f),
_phantom: Default::default(),
}
}
}
pub struct WithRequestPayloadSlice<'payload, S: Stack + ?Sized, Prev: Builder<S>> {
previous: Prev,
payload: &'payload [u8],
_phantom: core::marker::PhantomData<S>,
}
impl<'payload, S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>>
WithRequestPayloadSlice<'payload, S, Prev>
{
pub fn processing_response_payload_through<O, F2>(
self,
f: F2,
) -> ProcessingResponse<S, Self, O, F2>
where
F2: for<'a> FnOnce(&'a [u8]) -> O,
{
ProcessingResponse {
previous: self,
f: Some(f),
_phantom: Default::default(),
}
}
}
pub struct ProcessingResponse<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, O, F>
where
F: for<'a> FnOnce(&'a [u8]) -> O,
{
previous: Prev,
f: Option<F>,
_phantom: core::marker::PhantomData<S>,
}
macro_rules! code_macro {
($l:ident, $u:ident) => {
#[doc=concat!("A request sending the ", stringify!($u), " code")]
pub fn $l() -> Self {
Self {
code: coap_numbers::code::$u,
}
}
};
}
impl Code {
code_macro!(get, GET);
code_macro!(post, POST);
code_macro!(put, PUT);
code_macro!(delete, DELETE);
code_macro!(fetch, FETCH);
code_macro!(patch, PATCH);
code_macro!(ipatch, IPATCH);
pub fn with_path<S: Stack + ?Sized, P: conversions::AsUriPath>(
self,
path: P,
) -> WithPath<S, Self, P> {
WithPath {
previous: self,
path,
_phantom: Default::default(),
}
}
}
impl<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, P: conversions::AsUriPath>
WithPath<S, Prev, P>
{
pub fn with_request_callback<F>(self, f: F) -> WithRequestCallback<S, Self, F>
where
F: FnMut(&'_ mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>,
{
WithRequestCallback {
previous: self,
f,
_phantom: Default::default(),
}
}
pub fn with_request_payload_slice(
self,
payload: &[u8],
) -> WithRequestPayloadSlice<'_, S, Self> {
WithRequestPayloadSlice {
previous: self,
payload,
_phantom: Default::default(),
}
}
pub fn processing_response_payload_through<O, F>(
self,
f: F,
) -> ProcessingResponse<S, Self, O, F>
where
F: for<'a> FnOnce(&'a [u8]) -> O,
{
ProcessingResponse {
previous: self,
f: Some(f),
_phantom: Default::default(),
}
}
}
impl<S: Stack + ?Sized> Request<S> for Code {
type Carry = ();
type Output = Result<(), ()>;
async fn build_request(
&mut self,
req: &mut S::RequestMessage<'_>,
) -> Result<(), S::RequestUnionError> {
use coap_message::Code;
let code = <S::RequestMessage<'_> as MinimalWritableMessage>::Code::new(self.code)
.map_err(S::RequestMessage::convert_code_error)?;
req.set_code(code);
Ok(())
}
async fn process_response(&mut self, res: &S::ResponseMessage<'_>, _carry: ()) -> Self::Output {
let code: u8 = res.code().into();
use coap_numbers::code::{classify, Class, Range};
if !matches!(classify(code), Range::Response(Class::Success)) {
return Err(());
}
use coap_message_utils::OptionsExt;
res.options().ignore_elective_others().map_err(|_| ())
}
}
impl<S: Stack + ?Sized> Builder<S> for Code {}
impl<S: Stack + ?Sized, Prev: Builder<S>, P: conversions::AsUriPath> Request<S>
for WithPath<S, Prev, P>
{
type Carry = Prev::Carry;
type Output = Prev::Output;
async fn build_request(
&mut self,
req: &mut S::RequestMessage<'_>,
) -> Result<Self::Carry, S::RequestUnionError> {
use coap_message::OptionNumber;
let carry = <_ as coap_request::Request<S>>::build_request(&mut self.previous, req).await;
for p in self.path.as_uri_path() {
req.add_option(
<S::RequestMessage<'_> as MinimalWritableMessage>::OptionNumber::new(
coap_numbers::option::URI_PATH,
)
.map_err(S::RequestMessage::convert_option_number_error)?,
p.as_bytes(),
)
.map_err(S::RequestMessage::convert_add_option_error)?;
}
carry
}
async fn process_response(
&mut self,
res: &S::ResponseMessage<'_>,
carry: Prev::Carry,
) -> Self::Output {
<_ as coap_request::Request<S>>::process_response(&mut self.previous, res, carry).await
}
}
impl<S: Stack + ?Sized, Prev: Builder<S>, P: conversions::AsUriPath> Builder<S>
for WithPath<S, Prev, P>
{
}
impl<S: Stack + ?Sized, Prev: Builder<S>, F> Request<S> for WithRequestCallback<S, Prev, F>
where
F: FnMut(&mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>,
{
type Carry = Prev::Carry;
type Output = Prev::Output;
async fn build_request(
&mut self,
req: &mut S::RequestMessage<'_>,
) -> Result<Self::Carry, S::RequestUnionError> {
let carry = <_ as coap_request::Request<S>>::build_request(&mut self.previous, req).await?;
(self.f)(req)?;
Ok(carry)
}
async fn process_response(
&mut self,
res: &S::ResponseMessage<'_>,
carry: Self::Carry,
) -> Self::Output {
<_ as coap_request::Request<S>>::process_response(&mut self.previous, res, carry).await
}
}
impl<S: Stack + ?Sized, Prev: Builder<S>, F> Builder<S> for WithRequestCallback<S, Prev, F> where
F: FnMut(&mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>
{
}
impl<'payload, S: Stack + ?Sized, Prev: Builder<S>> Request<S>
for WithRequestPayloadSlice<'payload, S, Prev>
{
type Carry = Prev::Carry;
type Output = Prev::Output;
async fn build_request(
&mut self,
req: &mut S::RequestMessage<'_>,
) -> Result<Self::Carry, S::RequestUnionError> {
let carry = <_ as coap_request::Request<S>>::build_request(&mut self.previous, req).await?;
req.set_payload(self.payload)
.map_err(S::RequestMessage::convert_set_payload_error)?;
Ok(carry)
}
async fn process_response(
&mut self,
res: &S::ResponseMessage<'_>,
carry: Self::Carry,
) -> Self::Output {
<_ as coap_request::Request<S>>::process_response(&mut self.previous, res, carry).await
}
}
impl<'payload, S: Stack + ?Sized, Prev: Builder<S>> Builder<S>
for WithRequestPayloadSlice<'payload, S, Prev>
{
}
impl<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, O, F> Request<S>
for ProcessingResponse<S, Prev, O, F>
where
F: for<'a> FnOnce(&'a [u8]) -> O,
{
type Carry = Prev::Carry;
type Output = Result<O, ()>;
async fn build_request(
&mut self,
req: &mut S::RequestMessage<'_>,
) -> Result<Self::Carry, S::RequestUnionError> {
<_ as coap_request::Request<S>>::build_request(&mut self.previous, req).await
}
async fn process_response(
&mut self,
res: &S::ResponseMessage<'_>,
carry: Self::Carry,
) -> Self::Output {
<_ as coap_request::Request<S>>::process_response(&mut self.previous, res, carry).await?;
if let Some(f) = self.f.take() {
Ok(f(res.payload()))
} else {
Err(())
}
}
}
impl<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, O, F> Builder<S>
for ProcessingResponse<S, Prev, O, F>
where
F: for<'a> FnOnce(&'a [u8]) -> O,
{
}