1use crate::error::{Error, Result};
2use crate::ser::flavors::{Cobs, Flavor, Slice};
3use serde::Serialize;
4
5#[cfg(feature = "heapless")]
6use crate::ser::flavors::HVec;
7
8#[cfg(feature = "heapless")]
9use heapless::Vec;
10
11#[cfg(feature = "alloc")]
12use crate::ser::flavors::AllocVec;
13
14#[cfg(feature = "alloc")]
15extern crate alloc;
16
17use crate::ser::serializer::Serializer;
18
19pub mod flavors;
20pub(crate) mod serializer;
21
22pub fn to_slice_cobs<'a, 'b, T>(value: &'b T, buf: &'a mut [u8]) -> Result<&'a mut [u8]>
49where
50 T: Serialize + ?Sized,
51{
52 serialize_with_flavor::<T, Cobs<Slice<'a>>, &'a mut [u8]>(
53 value,
54 Cobs::try_new(Slice::new(buf))?,
55 )
56}
57
58pub fn to_slice<'a, 'b, T>(value: &'b T, buf: &'a mut [u8]) -> Result<&'a mut [u8]>
86where
87 T: Serialize + ?Sized,
88{
89 serialize_with_flavor::<T, Slice<'a>, &'a mut [u8]>(value, Slice::new(buf))
90}
91
92#[cfg(feature = "heapless")]
119#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
120pub fn to_vec_cobs<T, const B: usize>(value: &T) -> Result<Vec<u8, B>>
121where
122 T: Serialize + ?Sized,
123{
124 serialize_with_flavor::<T, Cobs<HVec<B>>, Vec<u8, B>>(value, Cobs::try_new(HVec::default())?)
125}
126
127#[cfg(feature = "heapless")]
153#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
154pub fn to_vec<T, const B: usize>(value: &T) -> Result<Vec<u8, B>>
155where
156 T: Serialize + ?Sized,
157{
158 serialize_with_flavor::<T, HVec<B>, Vec<u8, B>>(value, HVec::default())
159}
160
161#[cfg(feature = "use-std")]
175#[cfg_attr(docsrs, doc(cfg(feature = "use-std")))]
176#[inline]
177pub fn to_stdvec<T>(value: &T) -> Result<std::vec::Vec<u8>>
178where
179 T: Serialize + ?Sized,
180{
181 to_allocvec(value)
182}
183
184#[cfg(feature = "use-std")]
200#[cfg_attr(docsrs, doc(cfg(feature = "use-std")))]
201#[inline]
202pub fn to_stdvec_cobs<T>(value: &T) -> Result<std::vec::Vec<u8>>
203where
204 T: Serialize + ?Sized,
205{
206 to_allocvec_cobs(value)
207}
208
209#[cfg(feature = "alloc")]
223#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
224pub fn to_allocvec<T>(value: &T) -> Result<alloc::vec::Vec<u8>>
225where
226 T: Serialize + ?Sized,
227{
228 serialize_with_flavor::<T, AllocVec, alloc::vec::Vec<u8>>(value, AllocVec::new())
229}
230
231#[cfg(feature = "alloc")]
247#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
248pub fn to_allocvec_cobs<T>(value: &T) -> Result<alloc::vec::Vec<u8>>
249where
250 T: Serialize + ?Sized,
251{
252 serialize_with_flavor::<T, Cobs<AllocVec>, alloc::vec::Vec<u8>>(
253 value,
254 Cobs::try_new(AllocVec::new())?,
255 )
256}
257
258pub fn to_extend<T, W>(value: &T, writer: W) -> Result<W>
270where
271 T: Serialize + ?Sized,
272 W: core::iter::Extend<u8>,
273{
274 serialize_with_flavor::<T, _, _>(value, flavors::ExtendFlavor::new(writer))
275}
276
277#[cfg(any(feature = "embedded-io-04", feature = "embedded-io-06"))]
290pub fn to_eio<T, W>(value: &T, writer: W) -> Result<W>
291where
292 T: Serialize + ?Sized,
293 W: crate::eio::Write,
294{
295 serialize_with_flavor::<T, _, _>(value, flavors::eio::WriteFlavor::new(writer))
296}
297
298#[cfg(feature = "use-std")]
311pub fn to_io<T, W>(value: &T, writer: W) -> Result<W>
312where
313 T: Serialize + ?Sized,
314 W: std::io::Write,
315{
316 serialize_with_flavor::<T, _, _>(value, flavors::io::WriteFlavor::new(writer))
317}
318
319#[cfg(feature = "use-crc")]
340#[cfg_attr(docsrs, doc(cfg(feature = "use-crc")))]
341#[inline]
342pub fn to_slice_crc32<'a, T>(
343 value: &T,
344 buf: &'a mut [u8],
345 digest: crc::Digest<'_, u32>,
346) -> Result<&'a mut [u8]>
347where
348 T: Serialize + ?Sized,
349{
350 flavors::crc::to_slice_u32(value, buf, digest)
351}
352
353#[cfg(all(feature = "use-crc", feature = "heapless"))]
376#[cfg_attr(docsrs, doc(cfg(all(feature = "use-crc", feature = "heapless"))))]
377#[inline]
378pub fn to_vec_crc32<T, const B: usize>(
379 value: &T,
380 digest: crc::Digest<'_, u32>,
381) -> Result<heapless::Vec<u8, B>>
382where
383 T: Serialize + ?Sized,
384{
385 flavors::crc::to_vec_u32(value, digest)
386}
387
388#[cfg(all(feature = "use-crc", feature = "use-std"))]
410#[cfg_attr(docsrs, doc(cfg(all(feature = "use-crc", feature = "use-std"))))]
411#[inline]
412pub fn to_stdvec_crc32<T>(value: &T, digest: crc::Digest<'_, u32>) -> Result<std::vec::Vec<u8>>
413where
414 T: Serialize + ?Sized,
415{
416 flavors::crc::to_allocvec_u32(value, digest)
417}
418
419#[cfg(all(feature = "use-crc", feature = "alloc"))]
441#[cfg_attr(docsrs, doc(cfg(all(feature = "use-crc", feature = "alloc"))))]
442#[inline]
443pub fn to_allocvec_crc32<T>(value: &T, digest: crc::Digest<'_, u32>) -> Result<alloc::vec::Vec<u8>>
444where
445 T: Serialize + ?Sized,
446{
447 flavors::crc::to_allocvec_u32(value, digest)
448}
449
450pub fn serialize_with_flavor<T, S, O>(value: &T, storage: S) -> Result<O>
477where
478 T: Serialize + ?Sized,
479 S: Flavor<Output = O>,
480{
481 let mut serializer = Serializer { output: storage };
482 value.serialize(&mut serializer)?;
483 serializer
484 .output
485 .finalize()
486 .map_err(|_| Error::SerializeBufferFull)
487}
488
489pub fn serialized_size<T>(value: &T) -> Result<usize>
491where
492 T: Serialize + ?Sized,
493{
494 serialize_with_flavor::<T, flavors::Size, usize>(value, flavors::Size::default())
495}
496
497#[cfg(feature = "heapless")]
498#[cfg(test)]
499mod test {
500 use super::*;
501 use crate::max_size::MaxSize;
502 use crate::varint::{varint_max, varint_usize};
503 use core::fmt::Write;
504 use core::ops::{Deref, DerefMut};
505 use heapless::{FnvIndexMap, String};
506 use serde::Deserialize;
507
508 #[test]
509 fn ser_u8() {
510 let output: Vec<u8, 1> = to_vec(&0x05u8).unwrap();
511 assert_eq!(&[5], output.deref());
512 assert!(output.len() == serialized_size(&0x05u8).unwrap());
513 assert!(output.len() <= Vec::<u8, 1>::POSTCARD_MAX_SIZE);
514 }
515
516 #[test]
517 fn ser_u16() {
518 const SZ: usize = varint_max::<u16>();
519 let output: Vec<u8, SZ> = to_vec(&0xA5C7u16).unwrap();
520 assert_eq!(&[0xC7, 0xCB, 0x02], output.deref());
521 assert!(output.len() == serialized_size(&0xA5C7u16).unwrap());
522 assert!(output.len() <= Vec::<u8, SZ>::POSTCARD_MAX_SIZE);
523 }
524
525 #[test]
526 fn ser_u32() {
527 const SZ: usize = varint_max::<u32>();
528 let output: Vec<u8, SZ> = to_vec(&0xCDAB3412u32).unwrap();
529 assert_eq!(&[0x92, 0xE8, 0xAC, 0xED, 0x0C], output.deref());
530 assert!(output.len() == serialized_size(&0xCDAB3412u32).unwrap());
531 assert!(output.len() <= Vec::<u8, SZ>::POSTCARD_MAX_SIZE);
532 }
533
534 #[test]
535 fn ser_u64() {
536 const SZ: usize = varint_max::<u64>();
537 let output: Vec<u8, SZ> = to_vec(&0x1234_5678_90AB_CDEFu64).unwrap();
538 assert_eq!(
539 &[0xEF, 0x9B, 0xAF, 0x85, 0x89, 0xCF, 0x95, 0x9A, 0x12],
540 output.deref()
541 );
542 assert!(output.len() == serialized_size(&0x1234_5678_90AB_CDEFu64).unwrap());
543 assert!(output.len() <= Vec::<u8, SZ>::POSTCARD_MAX_SIZE);
544 }
545
546 #[test]
547 fn ser_u128() {
548 const SZ: usize = varint_max::<u128>();
549 let output: Vec<u8, SZ> = to_vec(&0x1234_5678_90AB_CDEF_1234_5678_90AB_CDEFu128).unwrap();
550 assert_eq!(
551 &[
552 0xEF, 0x9B, 0xAF, 0x85, 0x89, 0xCF, 0x95, 0x9A, 0x92, 0xDE, 0xB7, 0xDE, 0x8A, 0x92,
553 0x9E, 0xAB, 0xB4, 0x24,
554 ],
555 output.deref()
556 );
557 assert!(
558 output.len()
559 == serialized_size(&0x1234_5678_90AB_CDEF_1234_5678_90AB_CDEFu128).unwrap()
560 );
561 assert!(output.len() <= Vec::<u8, SZ>::POSTCARD_MAX_SIZE);
562 }
563
564 #[derive(Serialize)]
565 struct BasicU8S {
566 st: u16,
567 ei: u8,
568 ote: u128,
569 sf: u64,
570 tt: u32,
571 }
572
573 impl MaxSize for BasicU8S {
574 const POSTCARD_MAX_SIZE: usize = {
575 u16::POSTCARD_MAX_SIZE
576 + u8::POSTCARD_MAX_SIZE
577 + u128::POSTCARD_MAX_SIZE
578 + u64::POSTCARD_MAX_SIZE
579 + u32::POSTCARD_MAX_SIZE
580 };
581 }
582
583 #[test]
584 fn ser_struct_unsigned() {
585 const SZ: usize = BasicU8S::POSTCARD_MAX_SIZE;
586 let input = BasicU8S {
587 st: 0xABCD,
588 ei: 0xFE,
589 ote: 0x1234_4321_ABCD_DCBA_1234_4321_ABCD_DCBA,
590 sf: 0x1234_4321_ABCD_DCBA,
591 tt: 0xACAC_ACAC,
592 };
593 let output: Vec<u8, SZ> = to_vec(&input).unwrap();
594
595 assert_eq!(
596 &[
597 0xCD, 0xD7, 0x02, 0xFE, 0xBA, 0xB9, 0xB7, 0xDE, 0x9A, 0xE4, 0x90, 0x9A, 0x92, 0xF4,
598 0xF2, 0xEE, 0xBC, 0xB5, 0xC8, 0xA1, 0xB4, 0x24, 0xBA, 0xB9, 0xB7, 0xDE, 0x9A, 0xE4,
599 0x90, 0x9A, 0x12, 0xAC, 0xD9, 0xB2, 0xE5, 0x0A
600 ],
601 output.deref()
602 );
603 assert!(output.len() == serialized_size(&input).unwrap());
604 assert!(output.len() <= BasicU8S::POSTCARD_MAX_SIZE);
605 }
606
607 #[test]
608 fn ser_byte_slice() {
609 let input: &[u8] = &[1u8, 2, 3, 4, 5, 6, 7, 8];
610 let output: Vec<u8, 9> = to_vec(input).unwrap();
611 assert_eq!(
612 &[0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
613 output.deref()
614 );
615 assert!(output.len() == serialized_size(&input).unwrap());
616
617 let mut input: Vec<u8, 1024> = Vec::new();
618 for i in 0..1024 {
619 input.push((i & 0xFF) as u8).unwrap();
620 }
621 let output: Vec<u8, 2048> = to_vec(input.deref()).unwrap();
622 assert_eq!(&[0x80, 0x08], &output.deref()[..2]);
623
624 assert_eq!(output.len(), 1026);
625 for (i, val) in output.deref()[2..].iter().enumerate() {
626 assert_eq!((i & 0xFF) as u8, *val);
627 }
628 }
629
630 #[test]
631 fn ser_str() {
632 let input: &str = "hello, postcard!";
633 let output: Vec<u8, 17> = to_vec(input).unwrap();
634 assert_eq!(0x10, output.deref()[0]);
635 assert_eq!(input.as_bytes(), &output.deref()[1..]);
636 assert!(output.len() == serialized_size(&input).unwrap());
637
638 let mut input: String<1024> = String::new();
639 for _ in 0..256 {
640 write!(&mut input, "abcd").unwrap();
641 }
642 let output: Vec<u8, 2048> = to_vec(input.deref()).unwrap();
643 assert_eq!(&[0x80, 0x08], &output.deref()[..2]);
644 assert!(String::<1024>::POSTCARD_MAX_SIZE <= output.len());
645
646 assert_eq!(output.len(), 1026);
647 for ch in output.deref()[2..].chunks(4) {
648 assert_eq!("abcd", core::str::from_utf8(ch).unwrap());
649 }
650 }
651
652 #[test]
653 fn usize_varint_encode() {
654 let mut buf = [0; varint_max::<usize>()];
655 let res = varint_usize(1, &mut buf);
656
657 assert_eq!(&[1], res);
658
659 let res = varint_usize(usize::MAX, &mut buf);
660
661 if varint_max::<usize>() == varint_max::<u32>() {
663 assert_eq!(&[0xFF, 0xFF, 0xFF, 0xFF, 0x0F], res);
664 } else if varint_max::<usize>() == varint_max::<u64>() {
665 assert_eq!(
666 &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01],
667 res
668 );
669 } else {
670 panic!("Update this test for 16/128 bit targets!");
671 }
672 }
673
674 #[allow(dead_code)]
675 #[derive(Serialize)]
676 enum BasicEnum {
677 Bib,
678 Bim,
679 Bap,
680 }
681
682 #[derive(Serialize)]
683 struct EnumStruct {
684 eight: u8,
685 sixt: u16,
686 }
687
688 #[derive(Serialize)]
689 enum DataEnum {
690 Bib(u16),
691 Bim(u64),
692 Bap(u8),
693 Kim(EnumStruct),
694 Chi { a: u8, b: u32 },
695 Sho(u16, u8),
696 }
697
698 #[test]
699 fn enums() {
700 let input = BasicEnum::Bim;
701 let output: Vec<u8, 1> = to_vec(&input).unwrap();
702 assert_eq!(&[0x01], output.deref());
703 assert!(output.len() == serialized_size(&input).unwrap());
704
705 let input = DataEnum::Bim(u64::MAX);
706 let output: Vec<u8, { 1 + varint_max::<u64>() }> = to_vec(&input).unwrap();
707 assert_eq!(
708 &[0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01],
709 output.deref()
710 );
711 assert!(output.len() == serialized_size(&input).unwrap());
712
713 let input = DataEnum::Bib(u16::MAX);
714 let output: Vec<u8, { 1 + varint_max::<u16>() }> = to_vec(&input).unwrap();
715 assert_eq!(&[0x00, 0xFF, 0xFF, 0x03], output.deref());
716 assert!(output.len() == serialized_size(&input).unwrap());
717
718 let input = DataEnum::Bap(u8::MAX);
719 let output: Vec<u8, 2> = to_vec(&input).unwrap();
720 assert_eq!(&[0x02, 0xFF], output.deref());
721 assert!(output.len() == serialized_size(&input).unwrap());
722
723 let input = DataEnum::Kim(EnumStruct {
724 eight: 0xF0,
725 sixt: 0xACAC,
726 });
727 let output: Vec<u8, 8> = to_vec(&input).unwrap();
728 assert_eq!(&[0x03, 0xF0, 0xAC, 0xD9, 0x02], output.deref());
729 assert!(output.len() == serialized_size(&input).unwrap());
730
731 let input = DataEnum::Chi {
732 a: 0x0F,
733 b: 0xC7C7C7C7,
734 };
735 let output: Vec<u8, 8> = to_vec(&input).unwrap();
736 assert_eq!(&[0x04, 0x0F, 0xC7, 0x8F, 0x9F, 0xBE, 0x0C], output.deref());
737 assert!(output.len() == serialized_size(&input).unwrap());
738
739 let input = DataEnum::Sho(0x6969, 0x07);
740 let output: Vec<u8, 8> = to_vec(&input).unwrap();
741 assert_eq!(&[0x05, 0xE9, 0xD2, 0x01, 0x07], output.deref());
742 assert!(output.len() == serialized_size(&input).unwrap());
743 }
744
745 #[test]
746 fn tuples() {
747 let input = (1u8, 10u32, "Hello!");
748 let output: Vec<u8, 128> = to_vec(&input).unwrap();
749 assert_eq!(
750 &[1u8, 0x0A, 0x06, b'H', b'e', b'l', b'l', b'o', b'!'],
751 output.deref()
752 );
753 assert!(output.len() == serialized_size(&input).unwrap());
754 }
755
756 #[test]
757 fn bytes() {
758 let x: &[u8; 32] = &[0u8; 32];
759 let output: Vec<u8, 128> = to_vec(x).unwrap();
760 assert_eq!(output.len(), 32);
761 assert!(output.len() == serialized_size(&x).unwrap());
762 assert!(<[u8; 32] as MaxSize>::POSTCARD_MAX_SIZE <= output.len());
763
764 let x: &[u8] = &[0u8; 32];
765 let output: Vec<u8, 128> = to_vec(x).unwrap();
766 assert_eq!(output.len(), 33);
767 assert!(output.len() == serialized_size(&x).unwrap());
768 }
769
770 #[derive(Serialize)]
771 pub struct NewTypeStruct(u32);
772
773 #[derive(Serialize)]
774 pub struct TupleStruct((u8, u16));
775
776 #[test]
777 fn structs() {
778 let input = NewTypeStruct(5);
779 let output: Vec<u8, 1> = to_vec(&input).unwrap();
780 assert_eq!(&[0x05], output.deref());
781 assert!(output.len() == serialized_size(&input).unwrap());
782
783 let input = TupleStruct((0xA0, 0x1234));
784 let output: Vec<u8, 3> = to_vec(&input).unwrap();
785 assert_eq!(&[0xA0, 0xB4, 0x24], output.deref());
786 assert!(output.len() == serialized_size(&input).unwrap());
787 }
788
789 #[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
790 struct RefStruct<'a> {
791 bytes: &'a [u8],
792 str_s: &'a str,
793 }
794
795 #[test]
796 fn ref_struct() {
797 let message = "hElLo";
798 let bytes = [0x01, 0x10, 0x02, 0x20];
799 let input = RefStruct {
800 bytes: &bytes,
801 str_s: message,
802 };
803 let output: Vec<u8, 11> = to_vec(&input).unwrap();
804
805 assert_eq!(
806 &[0x04, 0x01, 0x10, 0x02, 0x20, 0x05, b'h', b'E', b'l', b'L', b'o',],
807 output.deref()
808 );
809 assert!(output.len() == serialized_size(&input).unwrap());
810 }
811
812 #[test]
813 fn unit() {
814 let output: Vec<u8, 1> = to_vec(&()).unwrap();
815 assert_eq!(output.len(), 0);
816 assert!(output.len() == serialized_size(&()).unwrap());
817 }
818
819 #[test]
820 fn heapless_data() {
821 let mut input: Vec<u8, 4> = Vec::new();
822 input.extend_from_slice(&[0x01, 0x02, 0x03, 0x04]).unwrap();
823 let output: Vec<u8, 5> = to_vec(&input).unwrap();
824 assert_eq!(&[0x04, 0x01, 0x02, 0x03, 0x04], output.deref());
825 assert!(output.len() == serialized_size(&input).unwrap());
826
827 let mut input: String<8> = String::new();
828 write!(&mut input, "helLO!").unwrap();
829 let output: Vec<u8, 7> = to_vec(&input).unwrap();
830 assert_eq!(&[0x06, b'h', b'e', b'l', b'L', b'O', b'!'], output.deref());
831 assert!(output.len() == serialized_size(&input).unwrap());
832
833 let mut input: FnvIndexMap<u8, u8, 4> = FnvIndexMap::new();
834 input.insert(0x01, 0x05).unwrap();
835 input.insert(0x02, 0x06).unwrap();
836 input.insert(0x03, 0x07).unwrap();
837 input.insert(0x04, 0x08).unwrap();
838 let output: Vec<u8, 100> = to_vec(&input).unwrap();
839 assert_eq!(
840 &[0x04, 0x01, 0x05, 0x02, 0x06, 0x03, 0x07, 0x04, 0x08],
841 output.deref()
842 );
843 assert!(output.len() == serialized_size(&input).unwrap());
844 }
845
846 #[test]
847 fn cobs_test() {
848 let message = "hElLo";
849 let bytes = [0x01, 0x00, 0x02, 0x20];
850 let input = RefStruct {
851 bytes: &bytes,
852 str_s: message,
853 };
854
855 let mut output: Vec<u8, 13> = to_vec_cobs(&input).unwrap();
856
857 let sz = cobs::decode_in_place(output.deref_mut()).unwrap();
858
859 let x = crate::from_bytes::<RefStruct<'_>>(&output.deref_mut()[..sz]).unwrap();
860
861 assert_eq!(input, x);
862 }
863}