use core::marker::PhantomData;
use crate::error::Error;
use crate::tlv::{TLVTag, TLVWrite};
use super::{Nullable, Octets, ToTLV, Utf8Str};
pub trait TLVBuilder<P>: Sized
where
P: TLVBuilderParent,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error>;
fn with<F>(self, f: F) -> Result<P, Error>
where
F: FnOnce(Self) -> Result<P, Error>,
{
f(self)
}
fn unchecked_into_parent(self) -> P;
}
#[cfg(not(feature = "defmt"))]
pub trait TLVBuilderParent: Sized + core::fmt::Debug {
type Write: TLVWrite;
fn writer(&mut self) -> &mut Self::Write;
}
#[cfg(feature = "defmt")]
pub trait TLVBuilderParent: Sized + core::fmt::Debug + defmt::Format {
type Write: TLVWrite;
fn writer(&mut self) -> &mut Self::Write;
}
pub struct TLVWriteParent<S, W>(S, W);
impl<S, W> TLVWriteParent<S, W> {
pub const fn new(id: S, writer: W) -> Self {
Self(id, writer)
}
}
impl<S, W> core::fmt::Debug for TLVWriteParent<S, W>
where
S: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.0)
}
}
#[cfg(feature = "defmt")]
impl<S, W> defmt::Format for TLVWriteParent<S, W>
where
S: core::fmt::Debug + defmt::Format,
{
fn format(&self, fmt: defmt::Formatter) {
defmt::write!(fmt, "{:?}", self.0);
}
}
#[cfg(not(feature = "defmt"))]
impl<S, W> TLVBuilderParent for TLVWriteParent<S, W>
where
S: core::fmt::Debug,
W: TLVWrite,
{
type Write = W;
fn writer(&mut self) -> &mut Self::Write {
&mut self.1
}
}
#[cfg(feature = "defmt")]
impl<S, W> TLVBuilderParent for TLVWriteParent<S, W>
where
S: core::fmt::Debug + defmt::Format,
W: TLVWrite,
{
type Write = W;
fn writer(&mut self) -> &mut Self::Write {
&mut self.1
}
}
pub struct ToTLVBuilder<P, T> {
parent: P,
tag: TLVTag,
_t: PhantomData<fn() -> T>,
}
impl<P, T> ToTLVBuilder<P, T>
where
P: TLVBuilderParent,
T: ToTLV + 'static,
{
pub fn new(parent: P, tag: &TLVTag) -> Self {
Self {
parent,
tag: tag.clone(),
_t: PhantomData,
}
}
#[cfg(not(feature = "defmt"))]
pub fn set(mut self, tlv: &T) -> Result<P, Error>
where
T: core::fmt::Debug,
{
#[cfg(feature = "log")]
log::debug!("{:?}::TLV -> {:?} +", self, tlv);
tlv.to_tlv(&self.tag, self.parent.writer())?;
Ok(self.parent)
}
#[cfg(feature = "defmt")]
pub fn set(mut self, tlv: &T) -> Result<P, Error>
where
T: core::fmt::Debug + defmt::Format,
{
defmt::debug!("{:?}::TLV[] -> {:?} +", self, tlv);
tlv.to_tlv(&self.tag, self.parent.writer())?;
Ok(self.parent)
}
}
impl<P, T> core::fmt::Debug for ToTLVBuilder<P, T>
where
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.parent)
}
}
#[cfg(feature = "defmt")]
impl<P, T> defmt::Format for ToTLVBuilder<P, T>
where
P: defmt::Format,
{
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{:?}", self.parent)
}
}
impl<P, T> TLVBuilderParent for ToTLVBuilder<P, T>
where
P: TLVBuilderParent,
{
type Write = P::Write;
fn writer(&mut self) -> &mut Self::Write {
self.parent.writer()
}
}
impl<P, T> TLVBuilder<P> for ToTLVBuilder<P, T>
where
P: TLVBuilderParent,
T: ToTLV + 'static,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
Ok(Self::new(parent, tag))
}
fn unchecked_into_parent(self) -> P {
self.parent
}
}
pub struct ToTLVArrayBuilder<P, T> {
_t: PhantomData<fn() -> T>,
parent: P,
}
impl<P, T> ToTLVArrayBuilder<P, T>
where
P: TLVBuilderParent,
T: ToTLV + 'static,
{
pub fn new(mut p: P, tag: &TLVTag) -> Result<Self, Error> {
p.writer().start_array(tag)?;
Ok(Self {
parent: p,
_t: PhantomData,
})
}
#[cfg(not(feature = "defmt"))]
pub fn push(mut self, tlv: &T) -> Result<Self, Error>
where
T: core::fmt::Debug,
{
#[cfg(feature = "log")]
log::debug!("{:?}::TLV[] -> {:?} +", self, tlv);
tlv.to_tlv(&TLVTag::Anonymous, self.parent.writer())?;
Ok(self)
}
#[cfg(feature = "defmt")]
pub fn push(mut self, tlv: &T) -> Result<Self, Error>
where
T: core::fmt::Debug + defmt::Format,
{
defmt::debug!("{:?}::TLV[] -> {:?} +", self, tlv);
tlv.to_tlv(&TLVTag::Anonymous, self.parent.writer())?;
Ok(self)
}
pub fn end(mut self) -> Result<P, Error> {
self.parent.writer().end_container()?;
Ok(self.parent)
}
}
impl<P, T> core::fmt::Debug for ToTLVArrayBuilder<P, T>
where
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}[]", self.parent)
}
}
#[cfg(feature = "defmt")]
impl<P, T> defmt::Format for ToTLVArrayBuilder<P, T>
where
P: defmt::Format,
{
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{:?}[]", self.parent)
}
}
impl<P, T> TLVBuilderParent for ToTLVArrayBuilder<P, T>
where
P: TLVBuilderParent,
{
type Write = P::Write;
fn writer(&mut self) -> &mut Self::Write {
self.parent.writer()
}
}
impl<P, T> TLVBuilder<P> for ToTLVArrayBuilder<P, T>
where
P: TLVBuilderParent,
T: ToTLV + 'static,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
Self::new(parent, tag)
}
fn unchecked_into_parent(self) -> P {
self.parent
}
}
pub struct Utf8StrBuilder<P> {
parent: P,
tag: TLVTag,
}
impl<P> Utf8StrBuilder<P>
where
P: TLVBuilderParent,
{
pub fn new(parent: P, tag: &TLVTag) -> Self {
Self {
parent,
tag: tag.clone(),
}
}
pub fn set(mut self, tlv: Utf8Str<'_>) -> Result<P, Error> {
#[cfg(feature = "defmt")]
defmt::debug!("{:?}::Utf8 -> {:?} +", self, tlv);
#[cfg(feature = "log")]
::log::debug!("{:?}::Utf8 -> {:?} +", self, tlv);
tlv.to_tlv(&self.tag, self.parent.writer())?;
Ok(self.parent)
}
}
impl<P> core::fmt::Debug for Utf8StrBuilder<P>
where
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.parent)
}
}
#[cfg(feature = "defmt")]
impl<P> defmt::Format for Utf8StrBuilder<P>
where
P: defmt::Format,
{
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{:?}", self.parent)
}
}
impl<P> TLVBuilderParent for Utf8StrBuilder<P>
where
P: TLVBuilderParent,
{
type Write = P::Write;
fn writer(&mut self) -> &mut Self::Write {
self.parent.writer()
}
}
impl<P> TLVBuilder<P> for Utf8StrBuilder<P>
where
P: TLVBuilderParent,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
Ok(Self::new(parent, tag))
}
fn unchecked_into_parent(self) -> P {
self.parent
}
}
pub struct Utf8StrArrayBuilder<P> {
parent: P,
}
impl<P> Utf8StrArrayBuilder<P>
where
P: TLVBuilderParent,
{
pub fn new(mut p: P, tag: &TLVTag) -> Result<Self, Error> {
p.writer().start_array(tag)?;
Ok(Self { parent: p })
}
pub fn push(mut self, tlv: Utf8Str<'_>) -> Result<Self, Error> {
#[cfg(feature = "defmt")]
defmt::debug!("{:?}::Utf8[] -> {:?} +", self, tlv);
#[cfg(feature = "log")]
::log::debug!("{:?}::Utf8[] -> {:?} +", self, tlv);
tlv.to_tlv(&TLVTag::Anonymous, self.parent.writer())?;
Ok(self)
}
pub fn end(mut self) -> Result<P, Error> {
self.parent.writer().end_container()?;
Ok(self.parent)
}
}
impl<P> core::fmt::Debug for Utf8StrArrayBuilder<P>
where
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}[]", self.parent)
}
}
#[cfg(feature = "defmt")]
impl<P> defmt::Format for Utf8StrArrayBuilder<P>
where
P: defmt::Format,
{
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{:?}[]", self.parent)
}
}
impl<P> TLVBuilderParent for Utf8StrArrayBuilder<P>
where
P: TLVBuilderParent,
{
type Write = P::Write;
fn writer(&mut self) -> &mut Self::Write {
self.parent.writer()
}
}
impl<P> TLVBuilder<P> for Utf8StrArrayBuilder<P>
where
P: TLVBuilderParent,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
Self::new(parent, tag)
}
fn unchecked_into_parent(self) -> P {
self.parent
}
}
pub struct OctetsBuilder<P> {
parent: P,
tag: TLVTag,
}
impl<P> OctetsBuilder<P>
where
P: TLVBuilderParent,
{
pub fn new(parent: P, tag: &TLVTag) -> Self {
Self {
parent,
tag: tag.clone(),
}
}
pub fn set(mut self, tlv: Octets<'_>) -> Result<P, Error> {
#[cfg(feature = "defmt")]
defmt::debug!("{:?}::Octets -> {:?} +", self, tlv);
#[cfg(feature = "log")]
::log::debug!("{:?}::Octets -> {:?} +", self, tlv);
tlv.to_tlv(&self.tag, self.parent.writer())?;
Ok(self.parent)
}
}
impl<P> core::fmt::Debug for OctetsBuilder<P>
where
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.parent)
}
}
#[cfg(feature = "defmt")]
impl<P> defmt::Format for OctetsBuilder<P>
where
P: defmt::Format,
{
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{:?}", self.parent)
}
}
impl<P> TLVBuilderParent for OctetsBuilder<P>
where
P: TLVBuilderParent,
{
type Write = P::Write;
fn writer(&mut self) -> &mut Self::Write {
self.parent.writer()
}
}
impl<P> TLVBuilder<P> for OctetsBuilder<P>
where
P: TLVBuilderParent,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
Ok(Self::new(parent, tag))
}
fn unchecked_into_parent(self) -> P {
self.parent
}
}
pub struct OctetsArrayBuilder<P> {
parent: P,
}
impl<P> OctetsArrayBuilder<P>
where
P: TLVBuilderParent,
{
pub fn new(mut p: P, tag: &TLVTag) -> Result<Self, Error> {
p.writer().start_array(tag)?;
Ok(Self { parent: p })
}
pub fn push(mut self, tlv: Octets<'_>) -> Result<Self, Error> {
#[cfg(feature = "defmt")]
defmt::debug!("{:?}::Octets[] -> {:?} +", self, tlv);
#[cfg(feature = "log")]
::log::debug!("{:?}::Octets[] -> {:?} +", self, tlv);
tlv.to_tlv(&TLVTag::Anonymous, self.parent.writer())?;
Ok(self)
}
pub fn end(mut self) -> Result<P, Error> {
self.parent.writer().end_container()?;
Ok(self.parent)
}
}
impl<P> core::fmt::Debug for OctetsArrayBuilder<P>
where
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}[]", self.parent)
}
}
#[cfg(feature = "defmt")]
impl<P> defmt::Format for OctetsArrayBuilder<P>
where
P: defmt::Format,
{
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{:?}[]", self.parent)
}
}
impl<P> TLVBuilderParent for OctetsArrayBuilder<P>
where
P: TLVBuilderParent,
{
type Write = P::Write;
fn writer(&mut self) -> &mut Self::Write {
self.parent.writer()
}
}
impl<P> TLVBuilder<P> for OctetsArrayBuilder<P>
where
P: TLVBuilderParent,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
Self::new(parent, tag)
}
fn unchecked_into_parent(self) -> P {
self.parent
}
}
pub struct NullableBuilder<P, T> {
parent: P,
tag: TLVTag,
_t: PhantomData<fn() -> T>,
}
impl<P, T> NullableBuilder<P, T>
where
P: TLVBuilderParent,
T: TLVBuilder<P>,
{
pub fn new(parent: P, tag: &TLVTag) -> Self {
Self {
parent,
tag: tag.clone(),
_t: PhantomData,
}
}
pub fn null(mut self) -> Result<P, Error> {
#[cfg(feature = "defmt")]
defmt::debug!("{:?}::nullable -> null +", self);
#[cfg(feature = "log")]
::log::debug!("{:?}::nullable -> null +", self);
self.parent.writer().null(&self.tag)?;
Ok(self.parent)
}
pub fn non_null(self) -> Result<T, Error> {
#[cfg(feature = "defmt")]
defmt::debug!("{:?}::nullable -> (not_null) +", self);
#[cfg(feature = "log")]
::log::debug!("{:?}::nullable -> (not_null) +", self);
T::new(self.parent, &self.tag)
}
pub fn with_non_null_if<F>(self, condition: bool, f: F) -> Result<P, Error>
where
F: FnOnce(T) -> Result<P, Error>,
{
if condition {
f(self.non_null()?)
} else {
self.null()
}
}
pub fn with_non_null<I, F>(self, input: Nullable<I>, f: F) -> Result<P, Error>
where
F: FnOnce(&I, T) -> Result<P, Error>,
{
if let Some(input) = input.as_opt_ref() {
f(input, self.non_null()?)
} else {
self.null()
}
}
}
impl<P, T> core::fmt::Debug for NullableBuilder<P, T>
where
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.parent)
}
}
#[cfg(feature = "defmt")]
impl<P, T> defmt::Format for NullableBuilder<P, T>
where
P: defmt::Format,
{
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{:?}", self.parent)
}
}
impl<P, T> TLVBuilderParent for NullableBuilder<P, T>
where
P: TLVBuilderParent,
{
type Write = P::Write;
fn writer(&mut self) -> &mut Self::Write {
self.parent.writer()
}
}
impl<P, T> TLVBuilder<P> for NullableBuilder<P, T>
where
P: TLVBuilderParent,
T: TLVBuilder<P>,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
Ok(Self::new(parent, tag))
}
fn unchecked_into_parent(self) -> P {
self.parent
}
}
pub struct OptionalBuilder<P, T> {
parent: P,
tag: TLVTag,
_t: PhantomData<fn() -> T>,
}
impl<P, T> OptionalBuilder<P, T>
where
P: TLVBuilderParent,
T: TLVBuilder<P>,
{
pub fn new(parent: P, tag: &TLVTag) -> Self {
Self {
parent,
tag: tag.clone(),
_t: PhantomData,
}
}
pub fn none(self) -> P {
#[cfg(feature = "defmt")]
defmt::debug!("{:?}::optional -> none +", self);
#[cfg(feature = "log")]
::log::debug!("{:?}::optional -> none +", self);
self.parent
}
pub fn some(self) -> Result<T, Error> {
#[cfg(feature = "defmt")]
defmt::debug!("{:?}::optional -> (some) +", self);
#[cfg(feature = "log")]
::log::debug!("{:?}::optional -> (some) +", self);
T::new(self.parent, &self.tag)
}
pub fn with_some_if<F>(self, condition: bool, f: F) -> Result<P, Error>
where
F: FnOnce(T) -> Result<P, Error>,
{
if condition {
f(self.some()?)
} else {
Ok(self.none())
}
}
pub fn with_some<I, F>(self, input: Option<I>, f: F) -> Result<P, Error>
where
F: FnOnce(&I, T) -> Result<P, Error>,
{
if let Some(input) = input.as_ref() {
f(input, self.some()?)
} else {
Ok(self.none())
}
}
}
impl<P, T> core::fmt::Debug for OptionalBuilder<P, T>
where
P: core::fmt::Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.parent)
}
}
#[cfg(feature = "defmt")]
impl<P, T> defmt::Format for OptionalBuilder<P, T>
where
P: defmt::Format,
{
fn format(&self, f: defmt::Formatter<'_>) {
defmt::write!(f, "{:?}", self.parent)
}
}
impl<P, T> TLVBuilderParent for OptionalBuilder<P, T>
where
P: TLVBuilderParent,
{
type Write = P::Write;
fn writer(&mut self) -> &mut Self::Write {
self.parent.writer()
}
}
impl<P, T> TLVBuilder<P> for OptionalBuilder<P, T>
where
P: TLVBuilderParent,
T: TLVBuilder<P>,
{
fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
Ok(Self::new(parent, tag))
}
fn unchecked_into_parent(self) -> P {
self.parent
}
}