use crate::properties::Property;
use crate::types::Properties;
use crate::{QoS, ResourceError, Retain};
use heapless::{String, Vec};
pub trait ToPayload {
type Error;
fn serialize(self, buffer: &mut [u8]) -> Result<usize, Self::Error>;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) struct ResponseTarget<'a> {
pub(crate) topic: &'a str,
pub(crate) correlation_data: Option<&'a [u8]>,
}
impl<'a> ResponseTarget<'a> {
pub(crate) fn publication<P>(self, payload: P) -> Publication<'a, P> {
let mut publication = Publication::new(self.topic, payload);
if let Some(data) = self.correlation_data {
publication = publication.correlate(data);
}
publication
}
pub(crate) fn to_owned<const TOPIC: usize, const CORRELATION: usize>(
self,
) -> Result<OwnedResponseTarget<TOPIC, CORRELATION>, ResourceError> {
Ok(OwnedResponseTarget {
topic: self
.topic
.try_into()
.map_err(|_| ResourceError::BufferTooSmall)?,
correlation_data: self
.correlation_data
.map(Vec::try_from)
.transpose()
.map_err(|_| ResourceError::BufferTooSmall)?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OwnedResponseTarget<const TOPIC: usize, const CORRELATION: usize> {
topic: String<TOPIC>,
correlation_data: Option<Vec<u8, CORRELATION>>,
}
impl<const TOPIC: usize, const CORRELATION: usize> OwnedResponseTarget<TOPIC, CORRELATION> {
pub fn topic(&self) -> &str {
self.topic.as_str()
}
pub fn correlation_data(&self) -> Option<&[u8]> {
self.correlation_data.as_deref()
}
pub fn publication<'a, P>(&'a self, payload: P) -> Publication<'a, P> {
let mut publication = Publication::new(self.topic.as_str(), payload);
if let Some(data) = self.correlation_data.as_deref() {
publication = publication.correlate(data);
}
publication
}
}
impl ToPayload for &[u8] {
type Error = ();
fn serialize(self, buffer: &mut [u8]) -> Result<usize, Self::Error> {
if buffer.len() < self.len() {
return Err(());
}
buffer[..self.len()].copy_from_slice(self);
Ok(self.len())
}
}
impl ToPayload for &str {
type Error = ();
fn serialize(self, buffer: &mut [u8]) -> Result<usize, Self::Error> {
self.as_bytes().serialize(buffer)
}
}
impl<E, F: FnOnce(&mut [u8]) -> Result<usize, E>> ToPayload for F {
type Error = E;
fn serialize(self, buffer: &mut [u8]) -> Result<usize, E> {
self(buffer)
}
}
pub struct Publication<'a, P> {
pub(crate) topic: &'a str,
pub(crate) properties: Properties<'a>,
pub(crate) qos: QoS,
pub(crate) payload: P,
pub(crate) retain: Retain,
}
impl<'a, P> Publication<'a, P> {
pub fn new(topic: &'a str, payload: P) -> Self {
Self {
payload,
qos: QoS::AtMostOnce,
topic,
properties: Properties::Slice(&[]),
retain: Retain::NotRetained,
}
}
pub fn properties_ref(&self) -> &Properties<'a> {
&self.properties
}
pub fn qos(mut self, qos: QoS) -> Self {
self.qos = qos;
self
}
pub fn retain(mut self) -> Self {
self.retain = Retain::Retained;
self
}
pub fn properties(mut self, properties: &'a [Property<'a>]) -> Self {
self.properties = self.properties.with_properties(properties);
self
}
pub fn correlate(mut self, data: &'a [u8]) -> Self {
self.properties = self.properties.with_correlation(data);
self
}
}
impl<'a> Publication<'a, &'a [u8]> {
pub fn bytes(topic: &'a str, payload: &'a [u8]) -> Self {
Self::new(topic, payload)
}
}
impl<'a> Publication<'a, &'a str> {
pub fn text(topic: &'a str, payload: &'a str) -> Self {
Self::new(topic, payload)
}
}