diff --git a/Cargo.lock b/Cargo.lock index 0ec47bf..223c8cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,7 +143,7 @@ dependencies = [ name = "dispatch-bundle" version = "0.1.0" dependencies = [ - "macros", + "embedded-command-macros 0.2.0", "serac", ] @@ -179,6 +179,28 @@ dependencies = [ "serac", ] +[[package]] +name = "embedded-command-macros" +version = "0.2.0" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "embedded-command-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9884ac9e0cbd689d3a600b303be44bfc073f3e8f932b97f4b6b82013df62962" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "embedded-hal" version = "0.2.7" @@ -279,16 +301,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "macros" -version = "0.1.0" -dependencies = [ - "Inflector", - "proc-macro2", - "quote", - "syn 2.0.96", -] - [[package]] name = "memchr" version = "2.7.1" @@ -431,13 +443,13 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serac" -version = "0.1.0" +version = "0.2.0" dependencies = [ "cortex-m", "cortex-m-rt", "defmt", + "embedded-command-macros 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "fill-array", - "macros", "panic-halt", ] diff --git a/macros/Cargo.toml b/macros/Cargo.toml index c8027a6..d01dd51 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embedded-command-macros" -version = "0.1.0" +version = "0.2.0" edition = "2024" description = "Macros for the embedded command crate family." license = "CC-BY-NC-SA-4.0" diff --git a/macros/src/serac/vanilla.rs b/macros/src/serac/vanilla.rs index 0c190f4..6d863c0 100644 --- a/macros/src/serac/vanilla.rs +++ b/macros/src/serac/vanilla.rs @@ -52,7 +52,7 @@ fn serialize_struct(s: DataStruct, info: &BodyInfo) -> TokenStream2 { let types: Vec<_> = s.fields.iter().map(|field| &field.ty).collect(); let (ser_body, deser_body) = match &s.fields { - Fields::Unit => (quote! { Ok(()) }, quote! { Ok(Self) }), + Fields::Unit => (quote! { Ok(0) }, quote! { Ok(Self) }), Fields::Unnamed(fields) => { let attr_tags: Vec<_> = fields .unnamed @@ -64,12 +64,13 @@ fn serialize_struct(s: DataStruct, info: &BodyInfo) -> TokenStream2 { ( quote! { let mut dst = dst.into_iter(); + let mut used = 0; #( - #path::SerializeIter::serialize_iter(&self.#attr_tags, &mut dst)?; + used += #path::SerializeIter::serialize_iter(&self.#attr_tags, &mut dst)?; )* - Ok(()) + Ok(used) }, quote! { let mut src = src.into_iter(); @@ -94,12 +95,13 @@ fn serialize_struct(s: DataStruct, info: &BodyInfo) -> TokenStream2 { ( quote! { let mut dst = dst.into_iter(); + let mut used = 0; #( - #path::SerializeIter::serialize_iter(&self.#attr_idents, &mut dst)?; + used += #path::SerializeIter::serialize_iter(&self.#attr_idents, &mut dst)?; )* - Ok(()) + Ok(used) }, quote! { let mut src = src.into_iter(); @@ -118,7 +120,7 @@ fn serialize_struct(s: DataStruct, info: &BodyInfo) -> TokenStream2 { quote! { impl #impl_generics #path::SerializeIter for #implementer #ty_generics #where_clause { - fn serialize_iter<'a>(&self, dst: impl IntoIterator::Word>) -> Result<(), #path::error::EndOfInput> + fn serialize_iter<'a>(&self, dst: impl IntoIterator::Word>) -> Result where <#path::encoding::vanilla::Vanilla as #path::encoding::Encoding>::Word: 'a, { @@ -189,12 +191,12 @@ fn serialize_enum(e: DataEnum, info: &BodyInfo, repr: Type) -> TokenStream2 { quote! { #ident(#(#idents),*) => { - #path::SerializeIter::serialize_iter(&#tag_const, &mut dst)?; + used += #path::SerializeIter::serialize_iter(&#tag_const, &mut dst)?; #( - #path::SerializeIter::serialize_iter(#idents, &mut dst)?; + used += #path::SerializeIter::serialize_iter(#idents, &mut dst)?; )* - Ok(()) + Ok(used) } } } @@ -207,12 +209,12 @@ fn serialize_enum(e: DataEnum, info: &BodyInfo, repr: Type) -> TokenStream2 { quote! { #ident{#(#idents),*} => { - #path::SerializeIter::serialize_iter(&#tag_const, &mut dst)?; + used += #path::SerializeIter::serialize_iter(&#tag_const, &mut dst)?; #( - #path::SerializeIter::serialize_iter(#idents, &mut dst)?; + used += #path::SerializeIter::serialize_iter(#idents, &mut dst)?; )* - Ok(()) + Ok(used) } } } @@ -260,11 +262,12 @@ fn serialize_enum(e: DataEnum, info: &BodyInfo, repr: Type) -> TokenStream2 { quote! { impl #impl_generics #path::SerializeIter for #implementer #ty_generics #where_clause { - fn serialize_iter<'a>(&self, dst: impl IntoIterator::Word>) -> Result<(), #path::error::EndOfInput> + fn serialize_iter<'a>(&self, dst: impl IntoIterator::Word>) -> Result where <#path::encoding::vanilla::Vanilla as #path::encoding::Encoding>::Word: 'a, { let mut dst = dst.into_iter(); + let mut used = 0; #( const #tag_consts: #repr = #tags; @@ -379,7 +382,7 @@ pub fn impl_serialize_buf(item: TokenStream) -> TokenStream { pub fn serialize_buf<'a>( &self, buf: &'a mut <#path::encoding::Vanilla as #path::Encoding>::Serialized<{ ::SIZE }>, - ) where + ) -> usize where &'a mut <#path::encoding::Vanilla as #path::Encoding>::Serialized<{ ::SIZE }>: IntoIterator::Word> + 'a, { diff --git a/serac/Cargo.toml b/serac/Cargo.toml index 870a4ba..e8555a1 100644 --- a/serac/Cargo.toml +++ b/serac/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "serac" -version = "0.1.0" +version = "0.2.0" edition = "2024" description = "A static, modular, and light-weight serialization framework." license = "CC-BY-NC-SA-4.0" repository = "https://github.com/adinack/embedded-command" [dependencies] -macros = { package = "embedded-command-macros", version = "0.1.0" } +macros = { package = "embedded-command-macros", version = "0.2.0" } fill-array = "0.2.1" # for binary diff --git a/serac/src/encoding/vanilla.rs b/serac/src/encoding/vanilla.rs index 409fceb..95aaa41 100644 --- a/serac/src/encoding/vanilla.rs +++ b/serac/src/encoding/vanilla.rs @@ -1,11 +1,12 @@ use core::{marker::PhantomData, mem::MaybeUninit}; +use fill_array::fill; + use super::Encoding; -use crate::{error, Medium, SerializeBuf, SerializeIter}; +use crate::{Medium, SerializeBuf, SerializeIter, error}; -use fill_array::fill; -// export proc macro +// reexport proc macros pub use macros::{SerializeBuf, SerializeIter}; pub struct Vanilla; @@ -27,7 +28,7 @@ macro_rules! impl_number { fn serialize_iter<'a>( &self, dst: impl IntoIterator::Word>, - ) -> Result<(), error::EndOfInput> + ) -> Result where ::Word: 'a, { @@ -40,7 +41,7 @@ macro_rules! impl_number { *dst.next().ok_or(error::EndOfInput)? = byte; } - Ok(()) + Ok($SIZE) } fn deserialize_iter<'a>( @@ -89,7 +90,7 @@ impl SerializeIter for bool { fn serialize_iter<'a>( &self, dst: impl IntoIterator::Word>, - ) -> Result<(), error::EndOfInput> + ) -> Result where ::Word: 'a, { @@ -97,7 +98,7 @@ impl SerializeIter for bool { *dst.next().ok_or(error::EndOfInput)? = if *self { 1 } else { 0 }; - Ok(()) + Ok(1) } fn deserialize_iter<'a>( @@ -126,17 +127,18 @@ impl SerializeIter for [T; N] { fn serialize_iter<'a>( &self, dst: impl IntoIterator::Word>, - ) -> Result<(), error::EndOfInput> + ) -> Result where ::Word: 'a, { let mut dst = dst.into_iter(); + let mut used = 0; for item in self { - item.serialize_iter(&mut dst)?; + used += item.serialize_iter(&mut dst)?; } - Ok(()) + Ok(used) } fn deserialize_iter<'a>( @@ -174,19 +176,20 @@ macro_rules! impl_tuple { fn serialize_iter<'a>( &self, dst: impl IntoIterator::Word>, - ) -> Result<(), error::EndOfInput> + ) -> Result where ::Word: 'a, { let mut dst = dst.into_iter(); + let mut used = 0; let ($($NAME,)+) = self; $( - $NAME.serialize_iter(&mut dst)?; + used += $NAME.serialize_iter(&mut dst)?; )+ - Ok(()) + Ok(used) } fn deserialize_iter<'a>( @@ -228,11 +231,11 @@ impl SerializeIter for PhantomData { fn serialize_iter<'a>( &self, _dst: impl IntoIterator::Word>, - ) -> Result<(), error::EndOfInput> + ) -> Result where ::Word: 'a, { - Ok(()) + Ok(0) } fn deserialize_iter<'a>( @@ -249,7 +252,7 @@ impl SerializeIter for PhantomData { mod tests { mod primitives { use crate as serac; - use serac::{error, SerializeIter}; + use serac::{SerializeIter, error}; macro_rules! iter_test { ($TYPE:ty) => { @@ -309,7 +312,7 @@ mod tests { use core::marker::PhantomData; use crate as serac; // for the proc macro - use serac::{buf, encoding::vanilla, SerializeBuf, SerializeIter}; + use serac::{SerializeBuf, SerializeIter, buf, encoding::vanilla}; mod structs { use super::*; @@ -338,7 +341,7 @@ mod tests { assert_eq!(3, buf.len()); let test_foo = Foo { a: 0xaa, b: -1 }; - test_foo.serialize_iter(&mut buf).unwrap(); + assert_eq!(3, test_foo.serialize_iter(&mut buf).unwrap()); let read_foo = Foo::deserialize_iter(&buf).unwrap(); @@ -348,7 +351,7 @@ mod tests { assert_eq!(3, buf.len()); let test_bar = Bar(0xaa, Nothing, -1); - test_bar.serialize_iter(&mut buf).unwrap(); + assert_eq!(3, test_bar.serialize_iter(&mut buf).unwrap()); let read_bar = Bar::deserialize_iter(&buf).unwrap(); @@ -361,7 +364,7 @@ mod tests { numbers: [0.; 16], flags: (false, 0xaa), }; - test_baz.serialize_iter(&mut buf).unwrap(); + assert_eq!(66, test_baz.serialize_iter(&mut buf).unwrap()); let read_baz = Baz::deserialize_iter(&buf).unwrap(); @@ -374,7 +377,7 @@ mod tests { assert_eq!(3, buf.len()); let test_foo = Foo { a: 0xaa, b: -1 }; - test_foo.serialize_buf(&mut buf); + assert_eq!(3, test_foo.serialize_buf(&mut buf)); let read_foo = Foo::deserialize_buf(&buf).unwrap(); @@ -384,7 +387,7 @@ mod tests { assert_eq!(3, buf.len()); let test_bar = Bar(0xaa, Nothing, -1); - test_bar.serialize_buf(&mut buf); + assert_eq!(3, test_bar.serialize_buf(&mut buf)); let read_bar = Bar::deserialize_buf(&buf).unwrap(); @@ -397,7 +400,7 @@ mod tests { numbers: [0.; 16], flags: (false, 0xaa), }; - test_baz.serialize_buf(&mut buf); + assert_eq!(66, test_baz.serialize_buf(&mut buf)); let read_baz = Baz::deserialize_buf(&buf).unwrap(); @@ -425,7 +428,14 @@ mod tests { assert_eq!(4, buf.len()); let test_foo = Foo::D { bar: 0xaa, t: -1 }; - test_foo.serialize_iter(&mut buf).unwrap(); + assert_eq!(4, test_foo.serialize_iter(&mut buf).unwrap()); + + let read_foo = Foo::deserialize_iter(&buf).unwrap(); + + assert_eq!(test_foo, read_foo); + + let test_foo = Foo::A; + assert_eq!(1, test_foo.serialize_iter(&mut buf).unwrap()); let read_foo = Foo::deserialize_iter(&buf).unwrap(); @@ -438,7 +448,14 @@ mod tests { assert_eq!(4, buf.len()); let test_foo = Foo::D { bar: 0xaa, t: -1 }; - test_foo.serialize_buf(&mut buf); + assert_eq!(4, test_foo.serialize_buf(&mut buf)); + + let read_foo = Foo::deserialize_buf(&buf).unwrap(); + + assert_eq!(test_foo, read_foo); + + let test_foo = Foo::A; + assert_eq!(1, test_foo.serialize_buf(&mut buf)); let read_foo = Foo::deserialize_buf(&buf).unwrap(); @@ -484,7 +501,7 @@ mod tests { let mut buf = [0; 8]; - test_bar.serialize_iter(&mut buf).unwrap(); + assert_eq!(6, test_bar.serialize_iter(&mut buf).unwrap()); let read_bar = SerializeIter::deserialize_iter(&buf).unwrap(); diff --git a/serac/src/lib.rs b/serac/src/lib.rs index 3896909..4e8b999 100644 --- a/serac/src/lib.rs +++ b/serac/src/lib.rs @@ -51,7 +51,7 @@ pub trait SerializeIter: Sized { fn serialize_iter<'a>( &self, dst: impl IntoIterator, - ) -> Result<(), error::EndOfInput> + ) -> Result where E::Word: 'a;