devela/data/codec/encode/
combinators.rs

1// devela::data::codec::encode::combinators
2//
3//! Defines
4//! [`CodecBe`], [`CodecIf`], [`CodecLe`], [`CodecFlags`], [`CodecJoin`], [`CodecLenValue`].
5//
6// TOC
7pub use {
8    cond::CodecIf,
9    endian::{CodecBe, CodecLe},
10    flags::CodecFlags,
11    join::CodecJoin,
12    len::{CodecLen, CodecLenValue},
13};
14
15use crate::{
16    iif, BitOr, Debug, Decodable, Deref, Encodable, EncodableLen, FmtResult, FmtWrite, Formatter,
17    IoError, IoErrorKind, IoRead, IoResult, IoTake, IoWrite, NonZero, PhantomData, TryFromIntError,
18};
19crate::_use! {basic::from_utf8}
20
21#[rustfmt::skip]
22mod endian {
23    use super::*;
24
25    /// Encodes and decodes a number in big-endian order.
26    ///
27    /// # Example
28    /// ```
29    /// use devela::{Encodable, CodecBe};
30    ///
31    /// let mut buf = [0u8; 32];
32    /// let len = CodecBe::new(1u16).encode(&mut &mut buf[..]).unwrap();
33    /// assert_eq!(&buf[..len], &[0, 1], "the most significant byte comes first");
34    ///
35    /// # #[cfg(feature = "alloc")] {
36    /// let mut buf = Vec::<u8>::new();
37    /// CodecBe::new(1u16).encode(&mut buf).unwrap();
38    /// assert_eq!(&buf, &[0, 1]);
39    /// # }
40    /// ```
41    #[doc = crate::doc_!(vendor: "encode")]
42    #[must_use]
43    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
44    pub struct CodecBe<W> {
45        num: W,
46    }
47    impl<W> CodecBe<W> {
48        /// Creates a new [`CodecBe`] combinator.
49        pub const fn new(num: W) -> Self { Self { num } }
50    }
51
52    /// Encodes and decodes a number in little-endian order.
53    ///
54    /// # Examples
55    /// ```
56    /// use devela::{Encodable, CodecLe};
57    ///
58    /// let mut buf = [0u8; 2];
59    /// let len = CodecLe::new(1u16).encode(&mut &mut buf[..]).unwrap();
60    /// assert_eq!(&buf[..len], &[1, 0], "the least significant byte comes first");
61    ///
62    /// # #[cfg(feature = "alloc")] {
63    /// let mut buf = Vec::<u8>::new();
64    /// CodecLe::new(1u16).encode(&mut buf).unwrap();
65    /// assert_eq!(&buf, &[1, 0]);
66    /// # }
67    /// ```
68    #[doc = crate::doc_!(vendor: "encode")]
69    #[must_use]
70    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
71    pub struct CodecLe<E> {
72        num: E,
73    }
74    impl<W> CodecLe<W> {
75        /// Creates a new [`CodecLe`] combinator.
76        pub const fn new(num: W) -> Self { Self { num } }
77    }
78    macro_rules! impl_endian {
79        () => {
80            impl_endian![int: u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, isize];
81            impl_endian![prim: usize]; impl_endian![non0: usize];
82            impl_endian![float: f32, f64];
83            // impl_endian![float: f16, f128]; // TODO
84        };
85        (int: $($T:ty),+) => {
86            impl_endian!(prim: $($T),+);
87            impl_endian!(non0: $($T),+);
88            $(
89                impl TryFrom<usize> for CodecBe<$T> {
90                    type Error = TryFromIntError;
91                    fn try_from(value: usize) -> Result<Self, Self::Error> {
92                        <$T>::try_from(value).map(Self::new)
93                    }
94                }
95                impl TryFrom<usize> for CodecLe<$T> {
96                    type Error = TryFromIntError;
97                    fn try_from(value: usize) -> Result<Self, Self::Error> {
98                        <$T>::try_from(value).map(Self::new)
99                    }
100                }
101            )+
102        };
103        (float: $($T:ty),+) => {
104            impl_endian!(prim: $($T),+);
105        };
106        (prim: $($T:ty),+) => {
107            $(  // Be
108                impl From<$T> for CodecBe<$T> { fn from(num: $T) -> Self { Self { num } } }
109                impl From<CodecBe<$T>> for $T { fn from(be: CodecBe<$T>) -> Self { be.num } }
110                impl<W: IoWrite> Encodable<W> for CodecBe<$T> {
111                    fn encode(&self, writer: &mut W) -> IoResult<usize> {
112                        writer.write(&self.num.to_be_bytes()) } }
113                impl<R: IoRead> Decodable<R> for CodecBe<$T> {
114                    type Output = $T;
115                    fn decode(reader: &mut R) -> IoResult<$T> {
116                        let mut buf = [0u8; size_of::<$T>()];
117                        reader.read_exact(&mut buf)?;
118                        Ok(<$T>::from_be_bytes(buf)) } }
119                // Le
120                impl From<$T> for CodecLe<$T> { fn from(num: $T) -> Self { Self { num } } }
121                impl From<CodecLe<$T>> for $T { fn from(be: CodecLe<$T>) -> Self { be.num } }
122                impl<W: IoWrite> Encodable<W> for CodecLe<$T> {
123                    fn encode(&self, writer: &mut W) -> IoResult<usize> {
124                        writer.write(&self.num.to_le_bytes()) } }
125                impl<R: IoRead> Decodable<R> for CodecLe<$T> {
126                    type Output= $T;
127                    fn decode(reader: &mut R) -> IoResult<$T> {
128                        let mut buf = [0u8; size_of::<$T>()];
129                        reader.read_exact(&mut buf)?;
130                        Ok(<$T>::from_le_bytes(buf)) } }
131            )+
132        };
133        (non0: $($T:ty),+) => {
134            $(  // Be
135                impl From<NonZero<$T>> for CodecBe<NonZero<$T>> {
136                    fn from(num: NonZero<$T>) -> Self { Self { num } } }
137                impl From<CodecBe<NonZero<$T>>> for NonZero<$T> {
138                    fn from(be: CodecBe<NonZero<$T>>) -> Self { be.num } }
139                impl<W: IoWrite> Encodable<W> for CodecBe<NonZero<$T>> {
140                    fn encode(&self, writer: &mut W) -> IoResult<usize> {
141                        writer.write(&self.num.get().to_be_bytes()) } }
142                impl<R: IoRead> Decodable<R> for CodecBe<NonZero<$T>> {
143                    type Output = NonZero<$T>;
144                    fn decode(reader: &mut R) -> IoResult<NonZero<$T>> {
145                        let mut buf = [0u8; size_of::<$T>()];
146                        reader.read_exact(&mut buf)?;
147                        let num = <$T>::from_be_bytes(buf);
148                        let non_zero = NonZero::<$T>::new(num)
149                            .ok_or(IoError::new(IoErrorKind::InvalidData,
150                                    "Decoded zero for NonZero type"))?;
151                        Ok(non_zero) } }
152                // Le
153                impl From<NonZero<$T>> for CodecLe<NonZero<$T>> {
154                    fn from(num: NonZero<$T>) -> Self { Self { num } } }
155                impl From<CodecLe<NonZero<$T>>> for NonZero<$T> {
156                    fn from(be: CodecLe<NonZero<$T>>) -> Self { be.num } }
157                impl<W: IoWrite> Encodable<W> for CodecLe<NonZero<$T>> {
158                    fn encode(&self, writer: &mut W) -> IoResult<usize> {
159                        writer.write(&self.num.get().to_be_bytes()) } }
160                impl<R: IoRead> Decodable<R> for CodecLe<NonZero<$T>> {
161                    type Output = NonZero<$T>;
162                    fn decode(reader: &mut R) -> IoResult<NonZero<$T>> {
163                        let mut buf = [0u8; size_of::<$T>()];
164                        reader.read_exact(&mut buf)?;
165                        let num = <$T>::from_le_bytes(buf);
166                        let non_zero = NonZero::<$T>::new(num)
167                            .ok_or(IoError::new(IoErrorKind::InvalidData,
168                                    "Decoded zero for NonZero type"))?;
169                        Ok(non_zero) } }
170            )+
171        }
172    }
173    impl_endian![];
174}
175#[rustfmt::skip]
176mod cond {
177    use super::*;
178
179    /// Encodes and decodes conditionally.
180    ///
181    /// # Example
182    /// ```
183    /// use devela::{Encodable, CodecIf, CStr};
184    ///
185    /// let non_empty = |s:&&CStr| !s.is_empty();
186    /// let mut buf = [0u8; 64];
187    /// let len = CodecIf::new(c"hello", non_empty).encode(&mut &mut buf[..]).unwrap();
188    /// assert_eq!(&buf[..len], b"hello\0", "A non-empty CStr includes the null terminator");
189    ///
190    /// let mut buf = [0u8; 64];
191    /// let len = CodecIf::new(c"", non_empty).encode(&mut &mut buf[..]).unwrap();
192    /// assert_eq!(&buf[..len], b"", "An empty CStr does not produce any output");
193    /// ```
194    #[doc = crate::doc_!(vendor: "encode")]
195    #[must_use]
196    #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
197    pub struct CodecIf<E, F> { encodable: E, condition: F }
198    impl<E, F: Fn(&E) -> bool> CodecIf<E, F> {
199        /// Creates a new [`CodecIf`] combinator.
200        pub const fn new(encodable: E, condition: F) -> Self { Self { encodable, condition } }
201    }
202    impl<E, F> AsRef<E> for CodecIf<E, F> { fn as_ref(&self) -> &E { &self.encodable } }
203    impl<E, F> Deref for CodecIf<E, F> {
204        type Target = E;
205        fn deref(&self) -> &Self::Target { self.as_ref() }
206    }
207    impl<E: Encodable<W>, W: IoWrite, F: Fn(&E) -> bool> Encodable<W> for CodecIf<E, F> {
208        fn encode(&self, writer: &mut W) -> IoResult<usize> {
209            if (self.condition)(&self.encodable) {
210                self.encodable.encode(writer)
211            } else {
212                Ok(0)
213            }
214        }
215    }
216}
217#[rustfmt::skip]
218mod flags {
219    use super::*;
220
221    /// Encodes and decodes a sequence of flags as a single byte.
222    ///
223    /// # Examples
224    /// ```
225    /// use devela::{Encodable, CodecFlags};
226    ///
227    /// let mut buf = [0u8; 1];
228    /// let len = CodecFlags::new([true, false, false, true, false, false, false, false])
229    ///     .encode(&mut &mut buf[..]).unwrap();
230    /// assert_eq!(&buf[..len], &[0b_1001_0000]);
231    ///
232    /// # #[cfg(feature = "alloc")] {
233    /// let mut buf = Vec::new();
234    /// CodecFlags::new([true, false, false, true, false, false, false, false])
235    ///     .encode(&mut buf).unwrap();
236    /// assert_eq!(&buf, &[0b_1001_0000]);
237    /// # }
238    /// ```
239    #[doc = crate::doc_!(vendor: "encode")]
240    #[must_use]
241    #[repr(transparent)]
242    #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
243    pub struct CodecFlags([bool; 8]);
244    impl CodecFlags {
245        /// Creates a new [`CodecFlags`] combinator from 8 `bool`s.
246        pub const fn new(flags: [bool; 8]) -> Self { Self(flags) }
247        /// Creates a new [`CodecFlags`] from a slice of `bool`s.
248        ///
249        /// Takes the first 8 `bool`s and fills missing with `false`.
250        pub fn from_slice(slice: &[bool]) -> Self {
251            let mut flags = [false; 8];
252            for (i, &b) in slice.iter().take(8).enumerate() { flags[i] = b; }
253            Self(flags)
254        }
255        /// Creates a new [`CodecFlags`] from a slice of arbitrary types.
256        ///
257        /// The closure `f` is run for each element.
258        pub fn from_iter<T, I, F>(iter: I, mut f: F) -> Self
259        where
260            I: IntoIterator<Item = T>,
261            F: FnMut(T) -> bool,
262        {
263            let mut flags = [false; 8];
264            for (i, v) in iter.into_iter().take(8).enumerate() {
265                flags[i] = f(v);
266            }
267            Self(flags)
268        }
269    }
270    impl Debug for CodecFlags {
271        fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult<()> {
272            write!(f, "CodecFlags({:08b})", u8::from(*self)) }
273    }
274    impl Deref for CodecFlags {
275        type Target = [bool; 8];
276        fn deref(&self) -> &Self::Target { &self.0 }
277    }
278    impl AsRef<[bool; 8]> for CodecFlags {
279        fn as_ref(&self) -> &[bool; 8] { &self.0 }
280    }
281    impl From<u8> for CodecFlags {
282        fn from(from: u8) -> Self {
283            let mut slice = [false; 8];
284            slice.iter_mut().enumerate().rev().for_each(|(i, v)| { *v = (from & (1 << i)) != 0; });
285            Self(slice) }
286    }
287    impl From<CodecFlags> for u8 {
288        fn from(from: CodecFlags) -> Self {
289            from.0.into_iter().rev().enumerate()
290                .filter_map(|(i, v)| v.then_some(1 << i)).fold(0u8, BitOr::bitor) }
291    }
292    impl<W: IoWrite> Encodable<W> for CodecFlags {
293        fn encode(&self, encoder: &mut W) -> IoResult<usize> {
294            u8::from(*self).encode(encoder) }
295    }
296}
297#[rustfmt::skip]
298mod join {
299    use super::*;
300
301    /// Encodes and decodes an iterator as a sequence with an optional `separator`.
302    ///
303    /// # Example
304    /// ```
305    /// use devela::{Encodable, CodecJoin};
306    ///
307    /// let compact_map = [ (c"hello", 1u8), (c"world", 2u8) ];
308    /// let mut buf = [0u8; 64];
309    /// let len = CodecJoin::new(&compact_map).encode(&mut &mut buf[..]).unwrap();
310    /// assert_eq!(&buf[..len], b"hello\0\x01world\0\x02");
311    ///
312    /// let mut buf = [0u8; 64];
313    /// let array = ["hello", "world", "another"];
314    /// let len = CodecJoin::with(&array, ", ").encode(&mut &mut buf[..]).unwrap();
315    /// assert_eq!(&buf[..len], b"hello, world, another");
316    ///
317    /// # #[cfg(feature = "alloc")] {
318    /// let mut buf = Vec::new();
319    /// // Note if you'd use '/' (a char) it would get encoded as [47, 0, 0, 0].
320    /// let len = CodecJoin::with(&array, "/").encode(&mut buf).unwrap();
321    /// assert_eq!(&buf, b"hello/world/another");
322    /// # }
323    /// ```
324    #[doc = crate::doc_!(vendor: "encode")]
325    #[must_use]
326    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
327    pub struct CodecJoin<E, S> {
328        encodable_iter: E,
329        separator: Option<S>,
330    }
331    impl<E> CodecJoin<E, ()> {
332        /// Creates a new [`CodecJoin`] combinator, without a separator.
333        pub const fn new(encodable_iter: E) -> Self {
334            Self { encodable_iter, separator: None::<()> }
335        }
336    }
337    impl<E, S> CodecJoin<E, S> {
338        /// Creates a new [`CodecJoin`] combinator with a `separator`.
339        pub const fn with(encodable_iter: E, separator: S) -> Self {
340            Self { encodable_iter, separator: Some(separator) }
341        }
342    }
343    impl<E, S, W: IoWrite> Encodable<W> for CodecJoin<E, S>
344    where
345        E: Clone + IntoIterator,
346        E::Item: Encodable<W>,
347        S: Encodable<W>,
348    {
349        fn encode(&self, writer: &mut W) -> IoResult<usize> {
350            let mut total = 0;
351            if let Some(sep) = &self.separator {
352                let mut is_first = true;
353                for encodable in self.encodable_iter.clone() {
354                    iif![is_first; is_first = false; total += sep.encode(writer)?];
355                    total += encodable.encode(writer)?;
356                }
357            } else {
358                for encodable in self.encodable_iter.clone() {
359                    total += encodable.encode(writer)?;
360                }
361            }
362            Ok(total)
363        }
364    }
365}
366#[rustfmt::skip]
367mod len {
368    use super::*;
369
370    /// A dummy writer that counts bytes instead of actually writing them.
371    ///
372    /// Note that this encoder runs all the same encoding logic as any other encoder,
373    /// so it will trigger the same side effects that other encoders would trigger
374    /// (e.g Allocations).
375    ///
376    /// # Example
377    /// ```
378    /// use devela::{IoWrite, Encodable, CodecLen};
379    ///
380    /// let encodable = c"hello, world!";
381    /// let mut encoder = CodecLen::new();
382    /// encodable.encode(&mut encoder).unwrap();
383    /// assert_eq!(encoder.size(), 14, "13 bytes from the ASCII string + 1 for the null terminator");
384    /// ```
385    #[doc = crate::doc_!(vendor: "encode")]
386    #[must_use]
387    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
388    pub struct CodecLen { size: usize, }
389    impl CodecLen {
390        /// Creates a new [`CodecLen`].
391        pub const fn new() -> Self { Self { size: 0 } }
392        /// Returns the computed encoded size.
393        pub const fn size(&self) -> usize { self.size }
394    }
395    impl From<CodecLen> for usize {
396        fn from(encoder: CodecLen) -> usize { encoder.size }
397    }
398    impl FmtWrite for CodecLen {
399        fn write_str(&mut self, s: &str) -> FmtResult<()> { self.size += s.len(); Ok(()) }
400    }
401    impl IoWrite for CodecLen {
402        fn write(&mut self, slice: &[u8]) -> IoResult<usize> { self.size += slice.len(); Ok(self.size) }
403        fn flush(&mut self) -> IoResult<()> { Ok(()) }
404    }
405
406    /// Encodes and decodes a length prefixed value
407    /// (<abbr title = "Type-Length-Value">[TLV]</abbr>).
408    ///
409    /// Encodes a value by **prefixing it with its length** using a fixed-size integer.
410    ///
411    /// The length must either be a `u8`, or explicitly encoded in either big-endian
412    /// by using [`CodecBe`] or little-endian by using [`CodecLe`].
413    ///
414    /// [TLV]: https://en.wikipedia.org/wiki/Type–length–value
415    ///
416    /// # Examples
417    /// ```
418    /// use devela::{Decodable, Encodable, CodecBe, CodecLenValue};
419    ///
420    /// // Non-allocating
421    /// let mut buf = [0u8; 64];
422    /// let len = CodecLenValue::<_, u8>::new("hello").encode(&mut &mut buf[..]).unwrap();
423    /// assert_eq!(&buf[..len], &[5, b'h', b'e', b'l', b'l', b'o']);
424    /// //
425    /// let mut reader = &buf[..];
426    /// let decoded: &str = CodecLenValue::<&str, u8>::decode(&mut &mut reader).unwrap();
427    /// assert_eq!(decoded, "hello");
428    ///
429    /// # #[cfg(feature = "alloc")] {
430    /// let lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
431    /// incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
432    /// exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
433    /// dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.";
434    /// // Allocating
435    /// let mut buf = Vec::new();
436    /// let len = CodecLenValue::<_, CodecBe<u16>>::new(lorem).encode(&mut buf).unwrap();
437    /// assert_eq!(&buf[..7], &[1, 78, b'L', b'o', b'r', b'e', b'm'], "A big-endian u16 len");
438    /// assert_eq![len, 336];
439    /// //
440    /// let mut reader = buf.as_slice();
441    /// let decoded: String = CodecLenValue::<String, CodecBe<u16>>::decode(&mut reader).unwrap();
442    /// assert_eq!(decoded, lorem);
443    /// # }
444    /// ```
445    ///
446    /// The length must fit the given type:
447    /// ```
448    /// # #[cfg(feature = "alloc")] {
449    /// use devela::{Encodable, CodecLe, CodecLenValue};
450    ///
451    /// let mut buf = Vec::new();
452    /// assert![CodecLenValue::<_, u8>::new("*".repeat(451)).encode(&mut buf).is_err()];
453    /// assert![CodecLenValue::<_, CodecLe<u16>>::new("*".repeat(451)).encode(&mut buf).is_ok()];
454    /// # }
455    /// ```
456    #[doc = crate::doc_!(vendor: "encode")]
457    #[must_use]
458    #[doc(alias("length", "prefix", "TLV"))]
459    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
460    #[repr(transparent)]
461    pub struct CodecLenValue<E, CodecEndian> {
462        encodable: E,
463        phantom: PhantomData<CodecEndian>,
464    }
465    impl<E, CodecEndian> CodecLenValue<E, CodecEndian> {
466        /// Creates a new <abbr title = "Type-Length-Value">TLV</abbr> combinator.
467        pub const fn new(encodable: E) -> Self { Self { encodable, phantom: PhantomData, } }
468    }
469    impl<E, CodecEndian, W: IoWrite> Encodable<W> for CodecLenValue<E, CodecEndian>
470    where
471        E: Encodable<W> + EncodableLen,
472        CodecEndian: From<<CodecEndian as CodecEndianLen>::Len> + Encodable<W> + CodecEndianLen,
473        <CodecEndian as CodecEndianLen>::Len: TryFrom<usize>,
474    {
475        fn encode(&self, writer: &mut W) -> IoResult<usize> {
476            let len = self.encodable.encoded_size()?;
477            let len = <<CodecEndian as CodecEndianLen>::Len as TryFrom<usize>>::try_from(len)
478                .map_err(|_| IoError::new(IoErrorKind::InvalidInput, "Length conversion failed"))?;
479            let mut total = CodecEndian::from(len).encode(writer)?;
480            total += self.encodable.encode(writer)?;
481            Ok(total)
482        }
483    }
484    impl<D, O, CodecEndian, R> Decodable<R> for CodecLenValue<D, CodecEndian>
485    where
486        // D must be decodable from an IoTake wrapping &mut R.
487        for<'i> D: Decodable<IoTake<&'i mut R>, Output = O>,
488        // CodecEndian decodes the length prefix from R and its output is the associated Len.
489        CodecEndian: Decodable<R, Output = <CodecEndian as CodecEndianLen>::Len> + CodecEndianLen,
490        R: IoRead,
491        for<'r> &'r mut R: IoRead,
492    {
493        type Output = O;
494        fn decode(reader: &mut R) -> IoResult<Self::Output> {
495            let len_encoded = CodecEndian::decode(reader)?;
496            let len: usize = len_encoded.try_into().map_err(|_| {
497                IoError::new(IoErrorKind::InvalidData, "Invalid length value")
498            })?;
499            let mut limited_reader = reader.take(len as u64);
500            D::decode(&mut limited_reader)
501        }
502    }
503
504    // Specialized implementation for &str.
505    impl<'a, CodecEndian> Decodable<&'a mut &'a [u8]> for CodecLenValue<&'a str, CodecEndian>
506    where
507        CodecEndian: CodecEndianLen + Decodable<&'a mut &'a [u8],
508            Output = <CodecEndian as CodecEndianLen>::Len>,
509        <CodecEndian as CodecEndianLen>::Len: TryInto<usize>,
510    {
511        type Output = &'a str;
512        fn decode(reader: &mut &'a mut &'a [u8]) -> IoResult<Self::Output> {
513            fn decode_str<'a>(buf: &mut &'a [u8], len: usize) -> IoResult<&'a str> {
514                if buf.len() < len {
515                    return Err(IoError::new(IoErrorKind::UnexpectedEof, "Not enough bytes"));
516                }
517                let (s_bytes, rest) = buf.split_at(len);
518                *buf = rest;
519                from_utf8(s_bytes)
520                    .map_err(|_| IoError::new(IoErrorKind::InvalidData, "Invalid UTF-8"))
521            }
522            let len_encoded = CodecEndian::decode(reader)?;
523            let len: usize = len_encoded.try_into().map_err(|_| {
524                IoError::new(IoErrorKind::InvalidData, "Invalid length value")
525            })?;
526            decode_str(reader, len)
527        }
528    }
529
530    /// A private helper trait to tie a length type to the endian codec.
531    ///
532    /// This trait ensures that `CodecLenValue` only accepts explicit endianness encoders
533    /// (`CodecBe<T>` or `CodecLe<T>`) for encoding and decoding length prefixes
534    /// using unsized primitives, or simply `u8` where endianess is irrelevant.
535    ///
536    /// Justifications:
537    /// - Only endianness matters when encoding a fixed-length integer.
538    /// - Prevents accidental misuse by requiring an explicit choice.
539    /// - Keeps the API clean and avoids unnecessary complexity.
540    trait CodecEndianLen { type Len: TryInto<usize> + TryFrom<usize>; }
541    macro_rules! impl_codec_endian_len { ($($T:ty),+) => { $(
542        impl CodecEndianLen for CodecLe<$T> { type Len = $T; }
543        impl CodecEndianLen for CodecBe<$T> { type Len = $T; }
544    )+ }; }
545    impl_codec_endian_len![u8, u16, u32, usize];
546    impl CodecEndianLen for u8 { type Len = u8; }
547}