flexiber/
traits.rs

1// pub use der::{Decodable, Encodable};
2//! Trait definitions
3
4use crate::{header::Header, Decoder, Encoder, Error, Length, Result, Tag, TaggedSlice};
5use core::convert::{TryFrom, TryInto};
6
7#[cfg(feature = "alloc")]
8use {alloc::vec::Vec, core::iter};
9
10#[cfg(any(feature = "heapless", feature = "alloc"))]
11use crate::ErrorKind;
12
13/// Decoding trait.
14///
15/// Decode out of decoder, which essentially is a slice of bytes.
16///
17/// One way to implement this trait is to implement `TryFrom<TaggedSlice<'_>, Error = Error>`.
18pub trait Decodable<'a>: Sized {
19    /// Attempt to decode this message using the provided decoder.
20    fn decode(decoder: &mut Decoder<'a>) -> Result<Self>;
21
22    /// Parse `Self` from the provided byte slice.
23    fn from_bytes(bytes: &'a [u8]) -> Result<Self> {
24        let mut decoder = Decoder::new(bytes);
25        let result = Self::decode(&mut decoder)?;
26        decoder.finish(result)
27    }
28}
29
30impl<'a, X> Decodable<'a> for X
31where
32    X: TryFrom<TaggedSlice<'a>, Error = Error>,
33{
34    fn decode(decoder: &mut Decoder<'a>) -> Result<Self> {
35        TaggedSlice::decode(decoder)
36            .and_then(Self::try_from)
37            .or_else(|e| decoder.error(e.kind()))
38    }
39}
40
41/// This implementation is quite gotcha-y, since only one byte is peeked.
42///
43/// It should evaluate to the desired tag via `Tag::try_from(byte)?`.
44impl<'a, T> Decodable<'a> for Option<T>
45where
46    T: Decodable<'a> + Tagged,
47{
48    fn decode(decoder: &mut Decoder<'a>) -> Result<Option<T>> {
49        if let Some(byte) = decoder.peek() {
50            debug_now!(
51                "comparing {} against {} interpreted as {}",
52                &T::tag(),
53                byte,
54                Tag::try_from(byte)?
55            );
56            if T::tag() == Tag::try_from(byte)? {
57                return T::decode(decoder).map(Some);
58            }
59        }
60        Ok(None)
61    }
62}
63
64/// Encoding trait.
65///
66/// Encode into encoder, which essentially is a mutable slice of bytes.
67///
68/// Additionally, the encoded length needs to be known without actually encoding.
69pub trait Encodable {
70    /// Compute the length of this value in bytes when encoded as BER-TLV
71    fn encoded_length(&self) -> Result<Length>;
72
73    /// Encode this value as BER-TLV using the provided [`Encoder`].
74    fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()>;
75
76    /// Encode this value to the provided byte slice, returning a sub-slice
77    /// containing the encoded message.
78    fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
79        let mut encoder = Encoder::new(buf);
80        self.encode(&mut encoder)?;
81        encoder.finish()
82    }
83
84    /// Encode this message as BER-TLV, appending it to the provided
85    /// byte vector.
86    #[cfg(feature = "alloc")]
87    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
88    fn encode_to_vec(&self, buf: &mut Vec<u8>) -> Result<Length> {
89        let expected_len = self.encoded_length()?.to_usize();
90        let current_len = buf.len();
91        buf.reserve(expected_len);
92        buf.extend(iter::repeat(0).take(expected_len));
93
94        // TODO(nickray): seems the original in `der` is incorrect here?
95        // let mut encoder = Encoder::new(buf);
96        let mut encoder = Encoder::new(&mut buf[current_len..]);
97        self.encode(&mut encoder)?;
98        let actual_len = encoder.finish()?.len();
99
100        if expected_len != actual_len {
101            return Err(ErrorKind::Underlength {
102                expected: expected_len.try_into()?,
103                actual: actual_len.try_into()?,
104            }
105            .into());
106        }
107
108        actual_len.try_into()
109    }
110
111    /// Serialize this message as a byte vector.
112    #[cfg(feature = "alloc")]
113    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
114    fn to_vec(&self) -> Result<Vec<u8>> {
115        let mut buf = Vec::new();
116        self.encode_to_vec(&mut buf)?;
117        Ok(buf)
118    }
119}
120
121#[cfg(feature = "heapless")]
122#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))]
123/// The equivalent of the `encode_to_vec` and `to_vec` methods.
124///
125/// Separate trait because the generic parameter `N` would make `Encodable` not object safe.
126pub trait EncodableHeapless: Encodable {
127    /// Encode this message as BER-TLV, appending it to the provided
128    /// heapless byte vector.
129    fn encode_to_heapless_vec<const N: usize>(
130        &self,
131        buf: &mut heapless::Vec<u8, N>,
132    ) -> Result<Length> {
133        let expected_len = self.encoded_length()?.to_usize();
134        let current_len = buf.len();
135        // TODO(nickray): add a specific error for "Overcapacity" conditional on heapless feature?
136        buf.resize_default(current_len + expected_len)
137            .map_err(|_| Error::from(ErrorKind::Overlength))?;
138
139        let mut encoder = Encoder::new(&mut buf[current_len..]);
140        self.encode(&mut encoder)?;
141        let actual_len = encoder.finish()?.len();
142
143        if expected_len != actual_len {
144            return Err(ErrorKind::Underlength {
145                expected: expected_len.try_into()?,
146                actual: actual_len.try_into()?,
147            }
148            .into());
149        }
150
151        actual_len.try_into()
152    }
153
154    /// Serialize this message as a byte vector.
155    fn to_heapless_vec<const N: usize>(&self) -> Result<heapless::Vec<u8, N>> {
156        let mut buf = heapless::Vec::new();
157        self.encode_to_heapless_vec(&mut buf)?;
158        Ok(buf)
159    }
160}
161
162#[cfg(feature = "heapless")]
163impl<X> EncodableHeapless for X where X: Encodable {}
164
165// /// Types with an associated BER-TLV [`Tag`].
166// pub trait Tagged {
167//     /// BER-TLV tag
168//     const TAG: Tag;
169// }
170
171/// Types with an associated BER-TLV [`Tag`].
172///
173/// A tagged type implementing `Container` has a blanked implementation of `Encodable`.
174pub trait Tagged {
175    /// The tag
176    fn tag() -> Tag;
177}
178
179/// Multiple encodables in a container.
180///
181/// A container implementing `Tagged` has a blanked implementation of `Encodable`.
182pub trait Container {
183    /// Call the provided function with a slice of [`Encodable`] trait objects
184    /// representing the fields of this message.
185    ///
186    /// This method uses a callback because structs with fields which aren't
187    /// directly [`Encodable`] may need to construct temporary values from
188    /// their fields prior to encoding.
189    fn fields<F, T>(&self, f: F) -> Result<T>
190    where
191        F: FnOnce(&[&dyn Encodable]) -> Result<T>;
192}
193
194impl<TaggedContainer> Encodable for TaggedContainer
195where
196    TaggedContainer: Tagged + Container,
197{
198    fn encoded_length(&self) -> Result<Length> {
199        #[allow(clippy::redundant_closure)]
200        // if we do as clippy tells, we get:
201        // 183 |         let value_length = self.fields(Length::try_from)?;
202        //     |                                 ^^^^^^ one type is more general than the other
203        //     |
204        //     = note: expected type `FnOnce<(&[&dyn Encodable],)>`
205        //                found type `FnOnce<(&[&dyn Encodable],)>`
206        let value_length = self.fields(|encodables| Length::try_from(encodables))?;
207        Header::new(Self::tag(), value_length)?.encoded_length() + value_length
208    }
209
210    fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
211        self.fields(|fields| encoder.encode_tagged_collection(Self::tag(), fields))
212    }
213}
214
215///// Multiple encodables, nested under a BER-TLV tag.
216/////
217///// This wraps up a common pattern for BER-TLV encoding.
218///// Implementations obtain a blanket `Encodable` implementation
219//pub trait TaggedContainer: Container + Tagged {}
220
221//pub trait Untagged {}
222
223///// Multiple encodables, side-by-side without a BER-TLV tag.
224/////
225///// This wraps up a common pattern for BER-TLV encoding.
226///// Implementations obtain a blanket `Encodable` implementation
227//pub trait UntaggedContainer: Container + Untagged {}
228
229// impl<UC> Encodable for UC
230// where
231//     UC: Untagged + Container,
232// {
233//     fn encoded_length(&self) -> Result<Length> {
234//         todo!();
235//         // let value_length = self.fields(|encodables| Length::try_from(encodables))?;
236//         // Header::new(Self::tag(), value_length)?.encoded_length() + value_length
237//     }
238
239//     fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
240//         todo!();
241//         // self.fields(|fields| encoder.nested(Self::tag(), fields))
242//     }
243// }
244
245// pub type UntaggedContainer<'a> = &'a [&'a dyn Encodable];
246
247// impl<'a> Encodable for UntaggedContainer<'a> {
248//     fn encoded_length(&self) -> Result<Length> {
249//        Length::try_from(*self)
250//     }
251
252//     fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
253//         for encodable in self.iter() {
254//             encodable.encode(encoder)?;
255//         }
256//         Ok(())
257//     }
258// }
259
260impl Encodable for &[u8] {
261    fn encoded_length(&self) -> Result<Length> {
262        self.len().try_into()
263    }
264
265    /// Encode this value as BER-TLV using the provided [`Encoder`].
266    fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
267        encoder.bytes(self)
268    }
269}
270
271// impl Encodable for Option<&[u8]> {
272//     fn encoded_length(&self) -> Result<Length> {
273//         match self {
274//             Some(slice) => slice.encoded_length(),
275//             None => Ok(Length::zero()),
276//         }
277//     }
278
279//     /// Encode this value as BER-TLV using the provided [`Encoder`].
280//     fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
281//         match self {
282//             Some(slice) => encoder.bytes(slice),
283//             None => Ok(())
284//         }
285//     }
286// }
287
288impl<T> Encodable for Option<T>
289where
290    T: Encodable,
291{
292    fn encoded_length(&self) -> Result<Length> {
293        match self {
294            Some(t) => t.encoded_length(),
295            None => Ok(Length::zero()),
296        }
297    }
298
299    /// Encode this value as BER-TLV using the provided [`Encoder`].
300    fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
301        match self {
302            Some(t) => t.encode(encoder),
303            None => Ok(()),
304        }
305    }
306}
307
308macro_rules! impl_array {
309    ($($N:literal),*) => {
310        $(
311            impl Encodable for [u8; $N] {
312                fn encoded_length(&self) -> Result<Length> {
313                    Ok(($N as u8).into())
314                }
315
316                /// Encode this value as BER-TLV using the provided [`Encoder`].
317                fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
318                    encoder.bytes(self.as_ref())
319                }
320            }
321
322            impl Decodable<'_> for [u8; $N] {
323                fn decode(decoder: &mut Decoder<'_>) -> Result<Self> {
324                    use core::convert::TryInto;
325                    let bytes: &[u8] = decoder.bytes($N as u8)?;
326                    Ok(bytes.try_into().unwrap())
327                }
328            }
329        )*
330    }
331}
332
333impl_array!(
334    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
335    26, 27, 28, 29, 30, 31, 32
336);
337
338#[cfg(test)]
339mod tests {
340
341    use super::{Container, Tagged};
342    use crate::{Decodable, Encodable, Error, Result, Tag, TagLike, TaggedSlice, TaggedValue};
343    use core::convert::TryFrom;
344
345    /// Types that can be tagged.
346    pub(crate) trait Taggable<T: TagLike>: Sized {
347        fn tagged(&self, tag: T) -> TaggedValue<&Self, T> {
348            TaggedValue::new(tag, self)
349        }
350    }
351
352    impl<T, X> Taggable<T> for X
353    where
354        X: Sized,
355        T: TagLike,
356    {
357    }
358
359    // The types [u8; 2], [u8; 3], [u8; 4] stand in here for any types for the fields
360    // of a struct that are Decodable + Encodable. This means they can decode to/encode from
361    // a byte slice, but also that thye can declare their encoded length.
362    //
363    // The goal then is to tag the struct definition for a proc-macro that implements
364    // nested BER-TLV objects (as this is what we need in PIV return values)
365
366    // tag 0xAA
367    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
368    struct S {
369        // tag 0x01
370        x: [u8; 2],
371        // tag 0x02
372        y: [u8; 3],
373        // tag 0x03
374        z: [u8; 4],
375    }
376
377    // this is what needs to be done to get `Decodable`
378    impl<'a> TryFrom<TaggedSlice<'a>> for S {
379        type Error = Error;
380
381        fn try_from(tagged_slice: TaggedSlice<'a>) -> Result<S> {
382            tagged_slice.tag().assert_eq(Tag::try_from(0x0A).unwrap())?;
383            tagged_slice.decode_nested(|decoder| {
384                let x = decoder.decode_tagged_value(Tag::try_from(0x01).unwrap())?;
385                let y = decoder.decode_tagged_value(Tag::try_from(0x02).unwrap())?;
386                let z = decoder.decode_tagged_value(Tag::try_from(0x03).unwrap())?;
387
388                Ok(Self { x, y, z })
389            })
390        }
391    }
392
393    // this is what needs to be done to get `Encodable`
394    impl Tagged for S {
395        fn tag() -> Tag {
396            Tag::try_from(0x0A).unwrap()
397        }
398    }
399
400    impl Container for S {
401        fn fields<F, T>(&self, field_encoder: F) -> Result<T>
402        where
403            F: FnOnce(&[&dyn Encodable]) -> Result<T>,
404        {
405            // both approaches equivalent
406            field_encoder(&[
407                &(Tag::try_from(0x01).unwrap().with_value(&self.x.as_ref())),
408                // &self.x.tagged(Tag::try_from(0x11).unwrap()),
409                &self.y.as_ref().tagged(Tag::try_from(0x02).unwrap()),
410                &self.z.as_ref().tagged(Tag::try_from(0x03).unwrap()),
411            ])
412        }
413    }
414
415    #[test]
416    fn reconstruct() {
417        let s = S {
418            x: [1, 2],
419            y: [3, 4, 5],
420            z: [6, 7, 8, 9],
421        };
422        let mut buf = [0u8; 1024];
423
424        let encoded = s.encode_to_slice(&mut buf).unwrap();
425
426        assert_eq!(
427            encoded,
428            &[0x0A, 15, 0x01, 2, 1, 2, 0x02, 3, 3, 4, 5, 0x03, 4, 6, 7, 8, 9,],
429        );
430
431        let s2 = S::from_bytes(encoded).unwrap();
432
433        assert_eq!(s, s2);
434    }
435
436    // tag 0xBB
437    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
438    struct T {
439        // tag 0x01
440        s: S,
441        // tag 0x02
442        t: [u8; 3],
443    }
444
445    impl<'a> TryFrom<TaggedSlice<'a>> for T {
446        type Error = Error;
447
448        fn try_from(tagged_slice: TaggedSlice<'a>) -> Result<Self> {
449            tagged_slice.tag().assert_eq(Tag::try_from(0x0B).unwrap())?;
450            tagged_slice.decode_nested(|decoder| {
451                let s = decoder.decode_tagged_value(Tag::try_from(0x01).unwrap())?;
452                let t = decoder.decode_tagged_value(Tag::try_from(0x02).unwrap())?;
453
454                Ok(Self { s, t })
455            })
456        }
457    }
458
459    impl Tagged for T {
460        fn tag() -> Tag {
461            Tag::try_from(0x0B).unwrap()
462        }
463    }
464
465    impl Container for T {
466        fn fields<F, Z>(&self, field_encoder: F) -> Result<Z>
467        where
468            F: FnOnce(&[&dyn Encodable]) -> Result<Z>,
469        {
470            field_encoder(&[
471                &self.s.tagged(Tag::try_from(0x1).unwrap()),
472                &self.t.as_ref().tagged(Tag::try_from(0x2).unwrap()),
473            ])
474        }
475    }
476
477    #[test]
478    fn nesty() {
479        let s = S {
480            x: [1, 2],
481            y: [3, 4, 5],
482            z: [6, 7, 8, 9],
483        };
484        let t = T {
485            s,
486            t: [0xA, 0xB, 0xC],
487        };
488
489        let mut buf = [0u8; 1024];
490
491        let encoded = t.encode_to_slice(&mut buf).unwrap();
492
493        assert_eq!(
494            encoded,
495            &[
496                0x0B, 24, 0x1, 17, 0x0A, 15, 0x01, 2, 1, 2, 0x02, 3, 3, 4, 5, 0x03, 4, 6, 7, 8, 9,
497                0x2, 3, 0xA, 0xB, 0xC
498            ],
499        );
500
501        let t2 = T::from_bytes(encoded).unwrap();
502
503        assert_eq!(t, t2);
504    }
505
506    // tag 0xCC
507    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
508    struct T2 {
509        // no tag
510        s: S,
511        // tag 0x02
512        t: [u8; 3],
513    }
514
515    impl<'a> TryFrom<TaggedSlice<'a>> for T2 {
516        type Error = Error;
517
518        fn try_from(tagged_slice: TaggedSlice<'a>) -> Result<Self> {
519            tagged_slice.tag().assert_eq(Tag::try_from(0x0C).unwrap())?;
520            tagged_slice.decode_nested(|decoder| {
521                let s = decoder.decode()?;
522                let t = decoder.decode_tagged_value(Tag::try_from(0x02).unwrap())?;
523
524                Ok(Self { s, t })
525            })
526        }
527    }
528
529    impl Tagged for T2 {
530        fn tag() -> Tag {
531            Tag::try_from(0x0C).unwrap()
532        }
533    }
534
535    impl Container for T2 {
536        fn fields<F, Z>(&self, field_encoder: F) -> Result<Z>
537        where
538            F: FnOnce(&[&dyn Encodable]) -> Result<Z>,
539        {
540            field_encoder(&[
541                &self.s,
542                &self.t.as_ref().tagged(Tag::try_from(0x2).unwrap()),
543            ])
544        }
545    }
546
547    #[test]
548    fn nesty2() {
549        let s = S {
550            x: [1, 2],
551            y: [3, 4, 5],
552            z: [6, 7, 8, 9],
553        };
554        let t = T2 {
555            s,
556            t: [0xA, 0xB, 0xC],
557        };
558
559        let mut buf = [0u8; 1024];
560
561        let encoded = t.encode_to_slice(&mut buf).unwrap();
562
563        assert_eq!(
564            encoded,
565            // &[0xBB, 24,
566            &[
567                0x0C, 22, // 0x1, 17,
568                0x0A, 15, 0x01, 2, 1, 2, 0x02, 3, 3, 4, 5, 0x03, 4, 6, 7, 8, 9, 0x2, 3, 0xA, 0xB,
569                0xC
570            ],
571        );
572
573        let t2 = T2::from_bytes(encoded).unwrap();
574
575        assert_eq!(t, t2);
576    }
577
578    // no tag
579    // #[derive(Clone, Copy, Debug, Eq, PartialEq)]
580    // struct T3 {
581    //     // no tag
582    //     s: S,
583    //     // tag 0x02
584    //     t: [u8; 3],
585    // }
586
587    // impl<'a> TryFrom<TaggedSlice<'a>> for T2 {
588    //     type Error = Error;
589
590    //     fn try_from(tagged_slice: TaggedSlice<'a>) -> Result<Self> {
591    //         tagged_slice.tag().assert_eq(Tag::try_from(0xCC).unwrap())?;
592    //         tagged_slice.decode_nested(|decoder| {
593    //             let s = decoder.decode()?;
594    //             let t = decoder.decode_tag(Tag::try_from(0x02).unwrap())?;
595
596    //             Ok(Self { s, t })
597    //         })
598    //     }
599    // }
600
601    // impl TaggedContainer for T2 {
602    //     fn tag() -> Tag {
603    //         Tag::try_from(0xCC).unwrap()
604    //     }
605
606    //     fn fields<F, Z>(&self, field_encoder: F) -> Result<Z>
607    //     where
608    //         F: FnOnce(&[&dyn Encodable]) -> Result<Z>,
609    //     {
610    //         field_encoder(&[
611    //             &self.s,
612    //             &self.t.tagged(Tag::try_from(0x2).unwrap()),
613    //         ])
614    //     }
615    // }
616
617    // #[test]
618    // fn nesty3() {
619    //     let s = S { x: [1,2], y: [3,4,5], z: [6,7,8,9] };
620    //     let t = T3 { s, t: [0xA, 0xB, 0xC] };
621
622    //     let mut buf = [0u8; 1024];
623
624    //     // let encoded = (&[
625    //     //     &t.s,
626    //     //     &t.t.tagged(Tag::try_from(0x2).unwrap()),
627    //     // ]).encode_to_slice(&mut buf).unwrap();
628
629    //     assert_eq!(encoded,
630    //         // &[0xBB, 24,
631    //         &[0xCC, 22,
632    //             // 0x1, 17,
633    //                 0xAA, 15,
634    //                     0x11, 2, 1, 2,
635    //                     0x22, 3, 3, 4, 5,
636    //                     0x33, 4, 6, 7, 8, 9,
637    //             0x2, 3,
638    //                0xA, 0xB, 0xC
639    //         ],
640    //     );
641
642    //     let t2 = T2::from_bytes(encoded).unwrap();
643
644    //     assert_eq!(t, t2);
645    // }
646    #[test]
647    fn derive_option() {
648        let mut buf = [0u8; 1024];
649        let s = S {
650            x: [1, 2],
651            y: [3, 4, 5],
652            z: [6, 7, 8, 9],
653        };
654        let encoded = s.encode_to_slice(&mut buf).unwrap();
655
656        let mut decoder = crate::Decoder::new(encoded);
657        let s: Option<S> = decoder.decode().unwrap();
658        assert!(s.is_some());
659
660        let empty = [0u8; 0];
661        let mut decoder = crate::Decoder::new(&empty);
662        let s: Option<S> = decoder.decode().unwrap();
663        assert!(s.is_none());
664    }
665}