mirror of
https://github.com/trussed-dev/flexiber.git
synced 2026-06-20 04:16:10 -07:00
Implement macros for untagged collections
This commit is contained in:
@@ -17,7 +17,7 @@ jobs:
|
||||
profile: minimal
|
||||
|
||||
- name: Build Documentation
|
||||
run: cargo doc --no-deps && scripts/make-toplevel-index.sh
|
||||
run: cargo doc --features derive && scripts/make-toplevel-index.sh
|
||||
|
||||
- name: Deploy Docs
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ license = "Apache-2.0 OR MIT"
|
||||
edition = "2018"
|
||||
description = "Encoding and decoding of SIMPLE-TLV as described in ISO 7816-4, without allocations."
|
||||
categories = ["cryptography", "data-structures", "encoding", "no-std"]
|
||||
keywords = ["crypto"]
|
||||
keywords = ["crypto", "no_std", "serialization"]
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
|
||||
+27
-15
@@ -3,7 +3,7 @@ use quote::{quote, ToTokens};
|
||||
use syn::{Attribute, DataStruct, Field, Ident};
|
||||
use synstructure::Structure;
|
||||
|
||||
use crate::{extract_attrs, FieldAttrs};
|
||||
use crate::{extract_attrs_optional_tag, FieldAttrs};
|
||||
|
||||
/// Derive Decodable on a struct
|
||||
pub(crate) struct DeriveDecodableStruct {
|
||||
@@ -17,7 +17,7 @@ pub(crate) struct DeriveDecodableStruct {
|
||||
impl DeriveDecodableStruct {
|
||||
pub fn derive(s: Structure<'_>, data: &DataStruct, name: &Ident, attrs: &[Attribute]) -> TokenStream {
|
||||
|
||||
let (tag, _) = extract_attrs(name, attrs);
|
||||
let (tag, _) = extract_attrs_optional_tag(name, attrs);
|
||||
|
||||
let mut state = Self {
|
||||
decode_fields: TokenStream::new(),
|
||||
@@ -56,26 +56,38 @@ impl DeriveDecodableStruct {
|
||||
}
|
||||
|
||||
/// Finish deriving a struct
|
||||
fn finish(self, s: &Structure<'_>, tag: u8) -> TokenStream {
|
||||
fn finish(self, s: &Structure<'_>, tag: Option<u8>) -> TokenStream {
|
||||
|
||||
let decode_fields = self.decode_fields;
|
||||
let decode_result = self.decode_result;
|
||||
|
||||
s.gen_impl(quote! {
|
||||
gen impl<'a> core::convert::TryFrom<simple_tlv::TaggedSlice<'a>> for @Self {
|
||||
type Error = simple_tlv::Error;
|
||||
if let Some(tag) = tag {
|
||||
s.gen_impl(quote! {
|
||||
gen impl<'a> core::convert::TryFrom<simple_tlv::TaggedSlice<'a>> for @Self {
|
||||
type Error = simple_tlv::Error;
|
||||
|
||||
fn try_from(tagged_slice: simple_tlv::TaggedSlice<'a>) -> simple_tlv::Result<Self> {
|
||||
use core::convert::TryInto;
|
||||
tagged_slice.tag().assert_eq(simple_tlv::Tag::try_from(#tag).unwrap())?;
|
||||
tagged_slice.decode_nested(|decoder| {
|
||||
#decode_fields
|
||||
fn try_from(tagged_slice: simple_tlv::TaggedSlice<'a>) -> simple_tlv::Result<Self> {
|
||||
use core::convert::TryInto;
|
||||
tagged_slice.tag().assert_eq(simple_tlv::Tag::try_from(#tag).unwrap())?;
|
||||
tagged_slice.decode_nested(|decoder| {
|
||||
#decode_fields
|
||||
|
||||
Ok(Self { #decode_result })
|
||||
})
|
||||
Ok(Self { #decode_result })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
s.gen_impl(quote! {
|
||||
gen impl<'a> simple_tlv::Decodable<'a> for @Self {
|
||||
fn decode(decoder: &mut simple_tlv::Decoder<'a>) -> simple_tlv::Result<Self> {
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
#decode_fields
|
||||
Ok(Self { #decode_result })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+46
-19
@@ -3,7 +3,7 @@ use quote::{quote, ToTokens};
|
||||
use syn::{Attribute, DataStruct, Field, Ident};
|
||||
use synstructure::Structure;
|
||||
|
||||
use crate::{extract_attrs, FieldAttrs};
|
||||
use crate::{extract_attrs_optional_tag, FieldAttrs};
|
||||
|
||||
/// Derive Encodable on a struct
|
||||
pub(crate) struct DeriveEncodableStruct {
|
||||
@@ -14,7 +14,7 @@ pub(crate) struct DeriveEncodableStruct {
|
||||
impl DeriveEncodableStruct {
|
||||
pub fn derive(s: Structure<'_>, data: &DataStruct, name: &Ident, attrs: &[Attribute]) -> TokenStream {
|
||||
|
||||
let (tag, _) = extract_attrs(name, attrs);
|
||||
let (tag, _) = extract_attrs_optional_tag(name, attrs);
|
||||
|
||||
let mut state = Self {
|
||||
encode_fields: TokenStream::new(),
|
||||
@@ -46,30 +46,57 @@ impl DeriveEncodableStruct {
|
||||
}
|
||||
|
||||
/// Finish deriving a struct
|
||||
fn finish(self, s: &Structure<'_>, tag: u8) -> TokenStream {
|
||||
fn finish(self, s: &Structure<'_>, tag: Option<u8>) -> TokenStream {
|
||||
|
||||
|
||||
let encode_fields = self.encode_fields;
|
||||
|
||||
s.gen_impl(quote! {
|
||||
gen impl simple_tlv::Tagged for @Self {
|
||||
fn tag() -> simple_tlv::Tag {
|
||||
// TODO(nickray): FIXME FIXME
|
||||
use core::convert::TryFrom;
|
||||
simple_tlv::Tag::try_from(#tag).unwrap()
|
||||
if let Some(tag) = tag {
|
||||
s.gen_impl(quote! {
|
||||
gen impl simple_tlv::Tagged for @Self {
|
||||
fn tag() -> simple_tlv::Tag {
|
||||
// TODO(nickray): FIXME FIXME
|
||||
use core::convert::TryFrom;
|
||||
simple_tlv::Tag::try_from(#tag).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen impl simple_tlv::Container for @Self {
|
||||
fn fields<F, T>(&self, field_encoder: F) -> simple_tlv::Result<T>
|
||||
where
|
||||
F: FnOnce(&[&dyn simple_tlv::Encodable]) -> simple_tlv::Result<T>,
|
||||
{
|
||||
use core::convert::TryFrom;
|
||||
field_encoder(&[#encode_fields])
|
||||
gen impl simple_tlv::Container for @Self {
|
||||
fn fields<F, T>(&self, field_encoder: F) -> simple_tlv::Result<T>
|
||||
where
|
||||
F: FnOnce(&[&dyn simple_tlv::Encodable]) -> simple_tlv::Result<T>,
|
||||
{
|
||||
use core::convert::TryFrom;
|
||||
field_encoder(&[#encode_fields])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
s.gen_impl(quote! {
|
||||
gen impl simple_tlv::Container for @Self {
|
||||
fn fields<F, T>(&self, field_encoder: F) -> simple_tlv::Result<T>
|
||||
where
|
||||
F: FnOnce(&[&dyn simple_tlv::Encodable]) -> simple_tlv::Result<T>,
|
||||
{
|
||||
use core::convert::TryFrom;
|
||||
field_encoder(&[#encode_fields])
|
||||
}
|
||||
}
|
||||
|
||||
gen impl simple_tlv::Encodable for @Self {
|
||||
fn encoded_length(&self) -> simple_tlv::Result<simple_tlv::Length> {
|
||||
use core::convert::TryFrom;
|
||||
use simple_tlv::Container;
|
||||
self.fields(|encodables| simple_tlv::Length::try_from(encodables))
|
||||
}
|
||||
|
||||
fn encode(&self, encoder: &mut simple_tlv::Encoder<'_>) -> simple_tlv::Result<()> {
|
||||
use simple_tlv::Container;
|
||||
self.fields(|fields| encoder.encode_untagged_collection(fields))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -95,7 +95,7 @@ impl FieldAttrs {
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_attrs(name: &Ident, attrs: &[Attribute]) -> (u8, bool) {
|
||||
fn extract_attrs_optional_tag(name: &Ident, attrs: &[Attribute]) -> (Option<u8>, bool) {
|
||||
let mut tag = None;
|
||||
let mut slice = false;
|
||||
|
||||
@@ -150,6 +150,12 @@ fn extract_attrs(name: &Ident, attrs: &[Attribute]) -> (u8, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
(tag, slice)
|
||||
}
|
||||
|
||||
fn extract_attrs(name: &Ident, attrs: &[Attribute]) -> (u8, bool) {
|
||||
let (tag, slice) = extract_attrs_optional_tag(name, attrs);
|
||||
|
||||
if let Some(tag) = tag {
|
||||
(tag, slice)
|
||||
} else {
|
||||
|
||||
@@ -75,6 +75,17 @@ impl<'a> Encoder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Encode a collection of values which impl the [`Encodable`] trait under a given tag.
|
||||
pub fn encode_untagged_collection(&mut self, encodables: &[&dyn Encodable]) -> Result<()> {
|
||||
let expected_len = Length::try_from(encodables)?;
|
||||
let mut nested_encoder = Encoder::new(self.reserve(expected_len)?);
|
||||
|
||||
for encodable in encodables {
|
||||
encodable.encode(&mut nested_encoder)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Encode a single byte into the backing buffer.
|
||||
pub(crate) fn byte(&mut self, byte: u8) -> Result<()> {
|
||||
match self.reserve(1u8)?.first_mut() {
|
||||
|
||||
+34
-1
@@ -22,6 +22,14 @@ struct T {
|
||||
x: [u8; 1234],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Decodable, Encodable, Eq, PartialEq)]
|
||||
struct T2 {
|
||||
#[tlv(tag = "0x44", slice)]
|
||||
x: [u8; 1234],
|
||||
#[tlv(tag = "0x55", slice)]
|
||||
a: [u8; 5],
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derived_reconstruct() {
|
||||
let s = S { x: [1,2], y: [3,4,5], z: [6,7,8,9] };
|
||||
@@ -38,7 +46,6 @@ fn derived_reconstruct() {
|
||||
);
|
||||
|
||||
let s2 = S::from_bytes(encoded).unwrap();
|
||||
|
||||
assert_eq!(s, s2);
|
||||
}
|
||||
|
||||
@@ -63,4 +70,30 @@ fn pretty_big() {
|
||||
// 1234
|
||||
0x44, 0xFF, 0x04, 0xD2]);
|
||||
assert_eq!(&encoded[8..], x);
|
||||
|
||||
let t2 = T::from_bytes(encoded).unwrap();
|
||||
assert_eq!(t, t2);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn derive_untagged() {
|
||||
let mut x = [0u8; 1234];
|
||||
for (i, x) in x.iter_mut().enumerate() {
|
||||
*x = i as _;
|
||||
};
|
||||
|
||||
let t = T2 { x, a: [17u8; 5] };
|
||||
|
||||
let mut buf = [0u8; 1500];
|
||||
let encoded = t.encode_to_slice(&mut buf).unwrap();
|
||||
|
||||
assert_eq!(&encoded[..4], [
|
||||
// 1234
|
||||
0x44, 0xFF, 0x04, 0xD2]);
|
||||
assert_eq!(&encoded[4..(encoded.len() - 7)], x);
|
||||
assert_eq!(&encoded[(encoded.len() - 7)..], [0x55, 5, 17, 17, 17, 17, 17]);
|
||||
|
||||
let t2 = T2::from_bytes(encoded).unwrap();
|
||||
assert_eq!(t, t2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user