1use core::marker::PhantomData;
217
218use crate::error::Error;
219use crate::tlv::{TLVTag, TLVWrite};
220
221use super::{Nullable, Octets, ToTLV, Utf8Str};
222
223pub trait TLVBuilder<P>: Sized
231where
232 P: TLVBuilderParent,
233{
234 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error>;
236
237 fn with<F>(self, f: F) -> Result<P, Error>
239 where
240 F: FnOnce(Self) -> Result<P, Error>,
241 {
242 f(self)
243 }
244
245 fn unchecked_into_parent(self) -> P;
255}
256
257#[cfg(not(feature = "defmt"))]
270pub trait TLVBuilderParent: Sized + core::fmt::Debug {
271 type Write: TLVWrite;
273
274 fn writer(&mut self) -> &mut Self::Write;
276}
277
278#[cfg(feature = "defmt")]
279pub trait TLVBuilderParent: Sized + core::fmt::Debug + defmt::Format {
280 type Write: TLVWrite;
282
283 fn writer(&mut self) -> &mut Self::Write;
285}
286
287pub struct TLVWriteParent<S, W>(S, W);
289
290impl<S, W> TLVWriteParent<S, W> {
291 pub const fn new(id: S, writer: W) -> Self {
293 Self(id, writer)
294 }
295}
296
297impl<S, W> core::fmt::Debug for TLVWriteParent<S, W>
298where
299 S: core::fmt::Debug,
300{
301 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
302 write!(f, "{:?}", self.0)
303 }
304}
305
306#[cfg(feature = "defmt")]
307impl<S, W> defmt::Format for TLVWriteParent<S, W>
308where
309 S: core::fmt::Debug + defmt::Format,
310{
311 fn format(&self, fmt: defmt::Formatter) {
312 defmt::write!(fmt, "{:?}", self.0);
313 }
314}
315
316#[cfg(not(feature = "defmt"))]
317impl<S, W> TLVBuilderParent for TLVWriteParent<S, W>
318where
319 S: core::fmt::Debug,
320 W: TLVWrite,
321{
322 type Write = W;
323
324 fn writer(&mut self) -> &mut Self::Write {
325 &mut self.1
326 }
327}
328
329#[cfg(feature = "defmt")]
330impl<S, W> TLVBuilderParent for TLVWriteParent<S, W>
331where
332 S: core::fmt::Debug + defmt::Format,
333 W: TLVWrite,
334{
335 type Write = W;
336
337 fn writer(&mut self) -> &mut Self::Write {
338 &mut self.1
339 }
340}
341
342pub struct ToTLVBuilder<P, T> {
350 parent: P,
351 tag: TLVTag,
352 _t: PhantomData<fn() -> T>,
353}
354
355impl<P, T> ToTLVBuilder<P, T>
356where
357 P: TLVBuilderParent,
358 T: ToTLV + 'static,
359{
360 pub fn new(parent: P, tag: &TLVTag) -> Self {
362 Self {
363 parent,
364 tag: tag.clone(),
365 _t: PhantomData,
366 }
367 }
368
369 #[cfg(not(feature = "defmt"))]
371 pub fn set(mut self, tlv: &T) -> Result<P, Error>
372 where
373 T: core::fmt::Debug,
374 {
375 #[cfg(feature = "log")]
376 log::debug!("{:?}::TLV -> {:?} +", self, tlv);
377
378 tlv.to_tlv(&self.tag, self.parent.writer())?;
379
380 Ok(self.parent)
381 }
382
383 #[cfg(feature = "defmt")]
384 pub fn set(mut self, tlv: &T) -> Result<P, Error>
385 where
386 T: core::fmt::Debug + defmt::Format,
387 {
388 defmt::debug!("{:?}::TLV[] -> {:?} +", self, tlv);
389
390 tlv.to_tlv(&self.tag, self.parent.writer())?;
391
392 Ok(self.parent)
393 }
394}
395
396impl<P, T> core::fmt::Debug for ToTLVBuilder<P, T>
397where
398 P: core::fmt::Debug,
399{
400 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
401 write!(f, "{:?}", self.parent)
402 }
403}
404
405#[cfg(feature = "defmt")]
406impl<P, T> defmt::Format for ToTLVBuilder<P, T>
407where
408 P: defmt::Format,
409{
410 fn format(&self, f: defmt::Formatter<'_>) {
411 defmt::write!(f, "{:?}", self.parent)
412 }
413}
414
415impl<P, T> TLVBuilderParent for ToTLVBuilder<P, T>
416where
417 P: TLVBuilderParent,
418{
419 type Write = P::Write;
420
421 fn writer(&mut self) -> &mut Self::Write {
422 self.parent.writer()
423 }
424}
425
426impl<P, T> TLVBuilder<P> for ToTLVBuilder<P, T>
427where
428 P: TLVBuilderParent,
429 T: ToTLV + 'static,
430{
431 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
432 Ok(Self::new(parent, tag))
433 }
434
435 fn unchecked_into_parent(self) -> P {
436 self.parent
437 }
438}
439
440pub struct ToTLVArrayBuilder<P, T> {
448 _t: PhantomData<fn() -> T>,
449 parent: P,
450}
451
452impl<P, T> ToTLVArrayBuilder<P, T>
453where
454 P: TLVBuilderParent,
455 T: ToTLV + 'static,
456{
457 pub fn new(mut p: P, tag: &TLVTag) -> Result<Self, Error> {
459 p.writer().start_array(tag)?;
460
461 Ok(Self {
462 parent: p,
463 _t: PhantomData,
464 })
465 }
466
467 #[cfg(not(feature = "defmt"))]
469 pub fn push(mut self, tlv: &T) -> Result<Self, Error>
470 where
471 T: core::fmt::Debug,
472 {
473 #[cfg(feature = "log")]
474 log::debug!("{:?}::TLV[] -> {:?} +", self, tlv);
475
476 tlv.to_tlv(&TLVTag::Anonymous, self.parent.writer())?;
477
478 Ok(self)
479 }
480
481 #[cfg(feature = "defmt")]
482 pub fn push(mut self, tlv: &T) -> Result<Self, Error>
483 where
484 T: core::fmt::Debug + defmt::Format,
485 {
486 defmt::debug!("{:?}::TLV[] -> {:?} +", self, tlv);
487
488 tlv.to_tlv(&TLVTag::Anonymous, self.parent.writer())?;
489
490 Ok(self)
491 }
492
493 pub fn end(mut self) -> Result<P, Error> {
495 self.parent.writer().end_container()?;
496
497 Ok(self.parent)
498 }
499}
500
501impl<P, T> core::fmt::Debug for ToTLVArrayBuilder<P, T>
502where
503 P: core::fmt::Debug,
504{
505 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
506 write!(f, "{:?}[]", self.parent)
507 }
508}
509
510#[cfg(feature = "defmt")]
511impl<P, T> defmt::Format for ToTLVArrayBuilder<P, T>
512where
513 P: defmt::Format,
514{
515 fn format(&self, f: defmt::Formatter<'_>) {
516 defmt::write!(f, "{:?}[]", self.parent)
517 }
518}
519
520impl<P, T> TLVBuilderParent for ToTLVArrayBuilder<P, T>
521where
522 P: TLVBuilderParent,
523{
524 type Write = P::Write;
525
526 fn writer(&mut self) -> &mut Self::Write {
527 self.parent.writer()
528 }
529}
530
531impl<P, T> TLVBuilder<P> for ToTLVArrayBuilder<P, T>
532where
533 P: TLVBuilderParent,
534 T: ToTLV + 'static,
535{
536 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
537 Self::new(parent, tag)
538 }
539
540 fn unchecked_into_parent(self) -> P {
541 self.parent
542 }
543}
544
545pub struct Utf8StrBuilder<P> {
547 parent: P,
548 tag: TLVTag,
549}
550
551impl<P> Utf8StrBuilder<P>
552where
553 P: TLVBuilderParent,
554{
555 pub fn new(parent: P, tag: &TLVTag) -> Self {
557 Self {
558 parent,
559 tag: tag.clone(),
560 }
561 }
562
563 pub fn set(mut self, tlv: Utf8Str<'_>) -> Result<P, Error> {
565 #[cfg(feature = "defmt")]
566 defmt::debug!("{:?}::Utf8 -> {:?} +", self, tlv);
567 #[cfg(feature = "log")]
568 ::log::debug!("{:?}::Utf8 -> {:?} +", self, tlv);
569
570 tlv.to_tlv(&self.tag, self.parent.writer())?;
571
572 Ok(self.parent)
573 }
574}
575
576impl<P> core::fmt::Debug for Utf8StrBuilder<P>
577where
578 P: core::fmt::Debug,
579{
580 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
581 write!(f, "{:?}", self.parent)
582 }
583}
584
585#[cfg(feature = "defmt")]
586impl<P> defmt::Format for Utf8StrBuilder<P>
587where
588 P: defmt::Format,
589{
590 fn format(&self, f: defmt::Formatter<'_>) {
591 defmt::write!(f, "{:?}", self.parent)
592 }
593}
594
595impl<P> TLVBuilderParent for Utf8StrBuilder<P>
596where
597 P: TLVBuilderParent,
598{
599 type Write = P::Write;
600
601 fn writer(&mut self) -> &mut Self::Write {
602 self.parent.writer()
603 }
604}
605
606impl<P> TLVBuilder<P> for Utf8StrBuilder<P>
607where
608 P: TLVBuilderParent,
609{
610 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
611 Ok(Self::new(parent, tag))
612 }
613
614 fn unchecked_into_parent(self) -> P {
615 self.parent
616 }
617}
618
619pub struct Utf8StrArrayBuilder<P> {
622 parent: P,
623}
624
625impl<P> Utf8StrArrayBuilder<P>
626where
627 P: TLVBuilderParent,
628{
629 pub fn new(mut p: P, tag: &TLVTag) -> Result<Self, Error> {
631 p.writer().start_array(tag)?;
632
633 Ok(Self { parent: p })
634 }
635
636 pub fn push(mut self, tlv: Utf8Str<'_>) -> Result<Self, Error> {
638 #[cfg(feature = "defmt")]
639 defmt::debug!("{:?}::Utf8[] -> {:?} +", self, tlv);
640 #[cfg(feature = "log")]
641 ::log::debug!("{:?}::Utf8[] -> {:?} +", self, tlv);
642
643 tlv.to_tlv(&TLVTag::Anonymous, self.parent.writer())?;
644
645 Ok(self)
646 }
647
648 pub fn end(mut self) -> Result<P, Error> {
650 self.parent.writer().end_container()?;
651
652 Ok(self.parent)
653 }
654}
655
656impl<P> core::fmt::Debug for Utf8StrArrayBuilder<P>
657where
658 P: core::fmt::Debug,
659{
660 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
661 write!(f, "{:?}[]", self.parent)
662 }
663}
664
665#[cfg(feature = "defmt")]
666impl<P> defmt::Format for Utf8StrArrayBuilder<P>
667where
668 P: defmt::Format,
669{
670 fn format(&self, f: defmt::Formatter<'_>) {
671 defmt::write!(f, "{:?}[]", self.parent)
672 }
673}
674
675impl<P> TLVBuilderParent for Utf8StrArrayBuilder<P>
676where
677 P: TLVBuilderParent,
678{
679 type Write = P::Write;
680
681 fn writer(&mut self) -> &mut Self::Write {
682 self.parent.writer()
683 }
684}
685
686impl<P> TLVBuilder<P> for Utf8StrArrayBuilder<P>
687where
688 P: TLVBuilderParent,
689{
690 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
691 Self::new(parent, tag)
692 }
693
694 fn unchecked_into_parent(self) -> P {
695 self.parent
696 }
697}
698
699pub struct OctetsBuilder<P> {
701 parent: P,
702 tag: TLVTag,
703}
704
705impl<P> OctetsBuilder<P>
706where
707 P: TLVBuilderParent,
708{
709 pub fn new(parent: P, tag: &TLVTag) -> Self {
711 Self {
712 parent,
713 tag: tag.clone(),
714 }
715 }
716
717 pub fn set(mut self, tlv: Octets<'_>) -> Result<P, Error> {
719 #[cfg(feature = "defmt")]
720 defmt::debug!("{:?}::Octets -> {:?} +", self, tlv);
721 #[cfg(feature = "log")]
722 ::log::debug!("{:?}::Octets -> {:?} +", self, tlv);
723
724 tlv.to_tlv(&self.tag, self.parent.writer())?;
725
726 Ok(self.parent)
727 }
728}
729
730impl<P> core::fmt::Debug for OctetsBuilder<P>
731where
732 P: core::fmt::Debug,
733{
734 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
735 write!(f, "{:?}", self.parent)
736 }
737}
738
739#[cfg(feature = "defmt")]
740impl<P> defmt::Format for OctetsBuilder<P>
741where
742 P: defmt::Format,
743{
744 fn format(&self, f: defmt::Formatter<'_>) {
745 defmt::write!(f, "{:?}", self.parent)
746 }
747}
748
749impl<P> TLVBuilderParent for OctetsBuilder<P>
750where
751 P: TLVBuilderParent,
752{
753 type Write = P::Write;
754
755 fn writer(&mut self) -> &mut Self::Write {
756 self.parent.writer()
757 }
758}
759
760impl<P> TLVBuilder<P> for OctetsBuilder<P>
761where
762 P: TLVBuilderParent,
763{
764 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
765 Ok(Self::new(parent, tag))
766 }
767
768 fn unchecked_into_parent(self) -> P {
769 self.parent
770 }
771}
772
773pub struct OctetsArrayBuilder<P> {
776 parent: P,
777}
778
779impl<P> OctetsArrayBuilder<P>
780where
781 P: TLVBuilderParent,
782{
783 pub fn new(mut p: P, tag: &TLVTag) -> Result<Self, Error> {
785 p.writer().start_array(tag)?;
786
787 Ok(Self { parent: p })
788 }
789
790 pub fn push(mut self, tlv: Octets<'_>) -> Result<Self, Error> {
792 #[cfg(feature = "defmt")]
793 defmt::debug!("{:?}::Octets[] -> {:?} +", self, tlv);
794 #[cfg(feature = "log")]
795 ::log::debug!("{:?}::Octets[] -> {:?} +", self, tlv);
796
797 tlv.to_tlv(&TLVTag::Anonymous, self.parent.writer())?;
798
799 Ok(self)
800 }
801
802 pub fn end(mut self) -> Result<P, Error> {
804 self.parent.writer().end_container()?;
805
806 Ok(self.parent)
807 }
808}
809
810impl<P> core::fmt::Debug for OctetsArrayBuilder<P>
811where
812 P: core::fmt::Debug,
813{
814 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
815 write!(f, "{:?}[]", self.parent)
816 }
817}
818
819#[cfg(feature = "defmt")]
820impl<P> defmt::Format for OctetsArrayBuilder<P>
821where
822 P: defmt::Format,
823{
824 fn format(&self, f: defmt::Formatter<'_>) {
825 defmt::write!(f, "{:?}[]", self.parent)
826 }
827}
828
829impl<P> TLVBuilderParent for OctetsArrayBuilder<P>
830where
831 P: TLVBuilderParent,
832{
833 type Write = P::Write;
834
835 fn writer(&mut self) -> &mut Self::Write {
836 self.parent.writer()
837 }
838}
839
840impl<P> TLVBuilder<P> for OctetsArrayBuilder<P>
841where
842 P: TLVBuilderParent,
843{
844 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
845 Self::new(parent, tag)
846 }
847
848 fn unchecked_into_parent(self) -> P {
849 self.parent
850 }
851}
852
853pub struct NullableBuilder<P, T> {
855 parent: P,
856 tag: TLVTag,
857 _t: PhantomData<fn() -> T>,
858}
859
860impl<P, T> NullableBuilder<P, T>
861where
862 P: TLVBuilderParent,
863 T: TLVBuilder<P>,
864{
865 pub fn new(parent: P, tag: &TLVTag) -> Self {
867 Self {
868 parent,
869 tag: tag.clone(),
870 _t: PhantomData,
871 }
872 }
873
874 pub fn null(mut self) -> Result<P, Error> {
876 #[cfg(feature = "defmt")]
877 defmt::debug!("{:?}::nullable -> null +", self);
878 #[cfg(feature = "log")]
879 ::log::debug!("{:?}::nullable -> null +", self);
880
881 self.parent.writer().null(&self.tag)?;
882
883 Ok(self.parent)
884 }
885
886 pub fn non_null(self) -> Result<T, Error> {
888 #[cfg(feature = "defmt")]
889 defmt::debug!("{:?}::nullable -> (not_null) +", self);
890 #[cfg(feature = "log")]
891 ::log::debug!("{:?}::nullable -> (not_null) +", self);
892
893 T::new(self.parent, &self.tag)
894 }
895
896 pub fn with_non_null_if<F>(self, condition: bool, f: F) -> Result<P, Error>
899 where
900 F: FnOnce(T) -> Result<P, Error>,
901 {
902 if condition {
903 f(self.non_null()?)
904 } else {
905 self.null()
906 }
907 }
908
909 pub fn with_non_null<I, F>(self, input: Nullable<I>, f: F) -> Result<P, Error>
912 where
913 F: FnOnce(&I, T) -> Result<P, Error>,
914 {
915 if let Some(input) = input.as_opt_ref() {
916 f(input, self.non_null()?)
917 } else {
918 self.null()
919 }
920 }
921}
922
923impl<P, T> core::fmt::Debug for NullableBuilder<P, T>
924where
925 P: core::fmt::Debug,
926{
927 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
928 write!(f, "{:?}", self.parent)
929 }
930}
931
932#[cfg(feature = "defmt")]
933impl<P, T> defmt::Format for NullableBuilder<P, T>
934where
935 P: defmt::Format,
936{
937 fn format(&self, f: defmt::Formatter<'_>) {
938 defmt::write!(f, "{:?}", self.parent)
939 }
940}
941
942impl<P, T> TLVBuilderParent for NullableBuilder<P, T>
943where
944 P: TLVBuilderParent,
945{
946 type Write = P::Write;
947
948 fn writer(&mut self) -> &mut Self::Write {
949 self.parent.writer()
950 }
951}
952
953impl<P, T> TLVBuilder<P> for NullableBuilder<P, T>
954where
955 P: TLVBuilderParent,
956 T: TLVBuilder<P>,
957{
958 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
959 Ok(Self::new(parent, tag))
960 }
961
962 fn unchecked_into_parent(self) -> P {
963 self.parent
964 }
965}
966
967pub struct OptionalBuilder<P, T> {
969 parent: P,
970 tag: TLVTag,
971 _t: PhantomData<fn() -> T>,
972}
973
974impl<P, T> OptionalBuilder<P, T>
975where
976 P: TLVBuilderParent,
977 T: TLVBuilder<P>,
978{
979 pub fn new(parent: P, tag: &TLVTag) -> Self {
981 Self {
982 parent,
983 tag: tag.clone(),
984 _t: PhantomData,
985 }
986 }
987
988 pub fn none(self) -> P {
990 #[cfg(feature = "defmt")]
991 defmt::debug!("{:?}::optional -> none +", self);
992 #[cfg(feature = "log")]
993 ::log::debug!("{:?}::optional -> none +", self);
994
995 self.parent
996 }
997
998 pub fn some(self) -> Result<T, Error> {
1000 #[cfg(feature = "defmt")]
1001 defmt::debug!("{:?}::optional -> (some) +", self);
1002 #[cfg(feature = "log")]
1003 ::log::debug!("{:?}::optional -> (some) +", self);
1004
1005 T::new(self.parent, &self.tag)
1006 }
1007
1008 pub fn with_some_if<F>(self, condition: bool, f: F) -> Result<P, Error>
1011 where
1012 F: FnOnce(T) -> Result<P, Error>,
1013 {
1014 if condition {
1015 f(self.some()?)
1016 } else {
1017 Ok(self.none())
1018 }
1019 }
1020
1021 pub fn with_some<I, F>(self, input: Option<I>, f: F) -> Result<P, Error>
1024 where
1025 F: FnOnce(&I, T) -> Result<P, Error>,
1026 {
1027 if let Some(input) = input.as_ref() {
1028 f(input, self.some()?)
1029 } else {
1030 Ok(self.none())
1031 }
1032 }
1033}
1034
1035impl<P, T> core::fmt::Debug for OptionalBuilder<P, T>
1036where
1037 P: core::fmt::Debug,
1038{
1039 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1040 write!(f, "{:?}", self.parent)
1041 }
1042}
1043
1044#[cfg(feature = "defmt")]
1045impl<P, T> defmt::Format for OptionalBuilder<P, T>
1046where
1047 P: defmt::Format,
1048{
1049 fn format(&self, f: defmt::Formatter<'_>) {
1050 defmt::write!(f, "{:?}", self.parent)
1051 }
1052}
1053
1054impl<P, T> TLVBuilderParent for OptionalBuilder<P, T>
1055where
1056 P: TLVBuilderParent,
1057{
1058 type Write = P::Write;
1059
1060 fn writer(&mut self) -> &mut Self::Write {
1061 self.parent.writer()
1062 }
1063}
1064
1065impl<P, T> TLVBuilder<P> for OptionalBuilder<P, T>
1066where
1067 P: TLVBuilderParent,
1068 T: TLVBuilder<P>,
1069{
1070 fn new(parent: P, tag: &TLVTag) -> Result<Self, Error> {
1071 Ok(Self::new(parent, tag))
1072 }
1073
1074 fn unchecked_into_parent(self) -> P {
1075 self.parent
1076 }
1077}