use coap_handler::{Attribute, Handler, Reporting};
use coap_handler_implementations::{
DeleteRenderable, FetchRenderable, GetRenderable, HandlerBuilder, IPatchRenderable,
PostRenderable, PutRenderable, ReportingHandlerBuilder, TypeHandler, TypeRenderable,
new_dispatcher, with_get_put_fetch,
};
use coap_message_utils::Error;
use core::default::Default;
use heapless::{String, Vec};
#[derive(minicbor::Decode, minicbor::Encode, Clone)]
#[cbor(map)]
pub struct MyCBOR {
#[n(0)]
hidden: bool,
#[n(1)]
number: usize,
#[cbor(n(2), with = "minicbor_adapters")]
label: String<32>,
#[cbor(n(3), with = "minicbor_adapters")]
list: Vec<usize, 16>,
}
impl Default for MyCBOR {
fn default() -> Self {
Self {
hidden: false,
number: 32,
label: "Hello".try_into().unwrap(),
list: Vec::from_slice(&[1, 2, 3]).expect("More than 3 entries allocated"),
}
}
}
impl GetRenderable for MyCBOR {
type Get = MyCBOR;
fn get(&mut self) -> Result<MyCBOR, Error> {
if self.hidden {
return Err(Error::forbidden());
}
Ok(self.clone())
}
}
impl PutRenderable for MyCBOR {
fn put(&mut self, new: &MyCBOR) -> Result<(), Error> {
if new.label.contains('<') {
return Err(Error::bad_request());
}
*self = new.clone();
Ok(())
}
type Put = MyCBOR;
}
pub struct MyCborView {
index: u8,
data: MyCBOR,
}
impl<C> minicbor::encode::Encode<C> for MyCborView {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self.index {
0 => e.encode(self.data.hidden),
1 => e.encode(self.data.number),
2 => e.encode(self.data.label.as_str()),
3 => e.encode(self.data.list.as_slice()),
_ => e.encode(()),
}?;
Ok(())
}
}
impl FetchRenderable for MyCBOR {
type FetchIn = u8;
type FetchOut = MyCborView;
fn fetch(&mut self, index: &Self::FetchIn) -> Result<Self::FetchOut, Error> {
let data = self.clone();
if data.hidden && *index >= 2 {
return Err(Error::forbidden());
}
Ok(MyCborView {
index: *index,
data,
})
}
}
pub fn single_cbor_tree() -> impl Handler + Reporting {
let cbor: MyCBOR = Default::default();
new_dispatcher()
.at_with_attributes(
&["cbor"],
&[Attribute::Ct(60)],
TypeHandler::new_minicbor_2(with_get_put_fetch(cbor)),
)
.with_wkc()
}
#[cfg(feature = "std")]
pub fn double_cbor_with_access() -> (
impl Handler + Reporting,
std::sync::Arc<std::sync::Mutex<MyCBOR>>,
) {
let cbor: std::sync::Arc<std::sync::Mutex<MyCBOR>> = Default::default();
let handler = new_dispatcher()
.at_with_attributes(
&["cbor", "1"],
&[],
TypeHandler::new_minicbor_2(with_get_put_fetch(TryingThroughMutex(cbor.clone()))),
)
.at_with_attributes(
&["cbor", "2"],
&[],
TypeHandler::new_minicbor_2(with_get_put_fetch(TryingThroughMutex(cbor.clone()))),
)
.with_wkc();
(handler, cbor)
}
#[cfg(feature = "std")]
pub struct TryingThroughMutex<T>(pub std::sync::Arc<std::sync::Mutex<T>>);
#[cfg(feature = "std")]
impl<T: TypeRenderable> TypeRenderable for TryingThroughMutex<T> {}
#[cfg(feature = "std")]
impl<T: GetRenderable> GetRenderable for TryingThroughMutex<T> {
type Get = T::Get;
fn get(&mut self) -> Result<Self::Get, Error> {
self.0
.try_lock()
.map_err(|_| Error::service_unavailable())?
.get()
}
}
#[cfg(feature = "std")]
impl<T: PutRenderable> PutRenderable for TryingThroughMutex<T> {
type Put = T::Put;
fn put(&mut self, new: &Self::Put) -> Result<(), Error> {
self.0
.try_lock()
.map(|mut s| s.put(new))
.unwrap_or(Err(Error::service_unavailable()))
}
}
#[cfg(feature = "std")]
impl<T: PostRenderable> PostRenderable for TryingThroughMutex<T> {
type PostIn = T::PostIn;
type PostOut = T::PostOut;
fn post(&mut self, request: &Self::PostIn) -> Result<Self::PostOut, Error> {
self.0
.try_lock()
.map(|mut s| s.post(request))
.unwrap_or(Err(Error::service_unavailable()))
}
}
#[cfg(feature = "std")]
impl<T: DeleteRenderable> DeleteRenderable for TryingThroughMutex<T> {}
#[cfg(feature = "std")]
impl<T: FetchRenderable> FetchRenderable for TryingThroughMutex<T> {
type FetchIn = T::FetchIn;
type FetchOut = T::FetchOut;
fn fetch(&mut self, request: &Self::FetchIn) -> Result<Self::FetchOut, Error> {
self.0
.try_lock()
.map(|mut s| s.fetch(request))
.unwrap_or(Err(Error::service_unavailable()))
}
}
#[cfg(feature = "std")]
impl<T: IPatchRenderable> IPatchRenderable for TryingThroughMutex<T> {
type IPatch = T::IPatch;
fn ipatch(&mut self, new: &Self::IPatch) -> Result<(), Error> {
self.0
.try_lock()
.map(|mut s| s.ipatch(new))
.unwrap_or(Err(Error::service_unavailable()))
}
}