diff --git a/Cargo.lock b/Cargo.lock index f61727c..97732ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,18 +42,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "cortex-m" version = "0.7.7" @@ -62,7 +50,7 @@ checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ "bare-metal", "bitfield", - "embedded-hal 0.2.7", + "embedded-hal", "volatile-register", ] @@ -86,27 +74,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "crc" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "critical-section" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" - [[package]] name = "defmt" version = "0.3.10" @@ -143,45 +110,13 @@ dependencies = [ name = "dispatch-bundle" version = "0.1.0" dependencies = [ - "embedded-command-macros 0.2.0", - "serac", -] - -[[package]] -name = "embassy-futures" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" - -[[package]] -name = "embassy-sync" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd938f25c0798db4280fcd8026bf4c2f48789aebf8f77b6e5cf8a7693ba114ec" -dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-util", - "heapless", -] - -[[package]] -name = "embedded-command" -version = "0.1.0" -dependencies = [ - "defmt", - "embassy-futures", - "embassy-sync", - "embedded-hal-async", - "embedded-io-async", - "heapless", + "embedded-command-macros 0.3.0", "serac", ] [[package]] name = "embedded-command-macros" -version = "0.2.0" +version = "0.3.0" dependencies = [ "Inflector", "proc-macro2", @@ -191,9 +126,9 @@ dependencies = [ [[package]] name = "embedded-command-macros" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9884ac9e0cbd689d3a600b303be44bfc073f3e8f932b97f4b6b82013df62962" +checksum = "f424c060861bb940cf4960cb69acd819a5c9748d6eb21b5adee2d2931355badd" dependencies = [ "Inflector", "proc-macro2", @@ -211,36 +146,6 @@ dependencies = [ "void", ] -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" -dependencies = [ - "embedded-hal 1.0.0", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "embedded-io-async" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" -dependencies = [ - "embedded-io", -] - [[package]] name = "fill-array" version = "0.2.1" @@ -252,49 +157,6 @@ dependencies = [ "syn 2.0.96", ] -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32", - "stable_deref_trait", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -322,32 +184,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" -[[package]] -name = "packit" -version = "0.1.0" -dependencies = [ - "crc", - "serac", -] - [[package]] name = "panic-halt" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11" -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -443,22 +285,16 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serac" -version = "0.2.1" +version = "0.3.0" dependencies = [ "cortex-m", "cortex-m-rt", "defmt", - "embedded-command-macros 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "embedded-command-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fill-array", "panic-halt", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "syn" version = "1.0.109" diff --git a/Cargo.toml b/Cargo.toml index 4e9e563..09c3629 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "3" members = [ "dispatch-bundle", "serac", - "embedded-command", + # "embedded-command", "macros", - "packit", + # "packit", ] diff --git a/ci.sh b/ci.sh index efb4065..4f86493 100755 --- a/ci.sh +++ b/ci.sh @@ -5,7 +5,7 @@ set -euxo pipefail rustup toolchain install nightly --component miri TARGETS=("thumbv6m-none-eabi" "thumbv7em-none-eabi" "thumbv7em-none-eabihf") -CRATES=("macros" "serac" "dispatch-bundle") +CRATES=("embedded-command-macros" "serac" "dispatch-bundle") # build @@ -24,14 +24,14 @@ done # miri -cargo +nightly miri test -p embedded-command command_buffer +# skip for now +# cargo +nightly miri test -p embedded-command command_buffer # clippy -cargo clippy +cargo clippy -- --deny warnings # crate-specific -# cookie-cutter - -# asm analysis +# serac +## asm analysis cargo build -p serac --bin asm --target thumbv7em-none-eabihf --features binary --release diff --git a/dispatch-bundle/src/lib.rs b/dispatch-bundle/src/lib.rs index a158d98..706e2fa 100644 --- a/dispatch-bundle/src/lib.rs +++ b/dispatch-bundle/src/lib.rs @@ -4,8 +4,8 @@ pub use macros::bundle; #[cfg(test)] mod tests { - use cookie_cutter::{encoding::vanilla, SerializeBuf}; use macros::bundle; + use serac::{buf, encoding::vanilla, SerializeBuf}; trait Foo { fn bar(&self) -> u8; @@ -126,7 +126,7 @@ mod tests { C = TEN, } - let mut buf = ::Serialized::default(); + let mut buf = buf!(MyBundle); MyBundle::C(C { val: 15, diff --git a/embedded-command/src/crc.rs b/embedded-command/src/crc.rs index 45955ed..727f813 100644 --- a/embedded-command/src/crc.rs +++ b/embedded-command/src/crc.rs @@ -1,18 +1,18 @@ use core::marker::PhantomData; -use cookie_cutter::SerializeIter; use iter::{CRCComputeIter, CRCComputeIterMut}; +use serac::SerializeIter; mod iter; #[derive(Debug)] pub enum Error { - Serialize(cookie_cutter::error::Error), + Serialize(serac::error::Error), Crc, } -impl From for Error { - fn from(value: cookie_cutter::error::Error) -> Self { +impl From for Error { + fn from(value: serac::error::Error) -> Self { Self::Serialize(value) } } @@ -48,7 +48,7 @@ impl> CRCPacket { &'a self, dst: impl IntoIterator, crc_provider: &'a mut C, - ) -> Result<(), cookie_cutter::error::EndOfInput> + ) -> Result<(), serac::error::EndOfInput> where C::Word: 'a, { @@ -87,7 +87,7 @@ impl> CRCPacket { #[cfg(test)] mod tests { - use cookie_cutter::encoding::vanilla; + use serac::encoding::vanilla; use super::*; diff --git a/macros/Cargo.toml b/macros/Cargo.toml index d01dd51..5fc6850 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embedded-command-macros" -version = "0.2.0" +version = "0.3.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 6d863c0..317655a 100644 --- a/macros/src/serac/vanilla.rs +++ b/macros/src/serac/vanilla.rs @@ -144,7 +144,7 @@ fn size_of_struct(s: DataStruct, info: &BodyInfo) -> TokenStream2 { if types.is_empty() { quote! { 0 } } else { - quote! { #( <#types as #path::SerializeBuf>::SIZE )+* } + quote! { #( <#types as #path::Size>::SIZE )+* } } } @@ -312,7 +312,7 @@ fn size_of_enum(e: DataEnum, info: &BodyInfo, repr: Type) -> TokenStream2 { if !variant.fields.is_empty() { let types: Vec<_> = variant.fields.iter().map(|field| &field.ty).collect(); - Some(quote! { #(<#types as #path::SerializeBuf>::SIZE)+* }) + Some(quote! { #(<#types as #path::Size>::SIZE)+* }) } else { None } @@ -328,7 +328,7 @@ fn size_of_enum(e: DataEnum, info: &BodyInfo, repr: Type) -> TokenStream2 { } )* - max + <#repr as #path::SerializeBuf>::SIZE + max + <#repr as #path::Size>::SIZE }} } @@ -373,36 +373,11 @@ pub fn impl_serialize_buf(item: TokenStream) -> TokenStream { let ident = info.ident; quote! { - unsafe impl #path::SerializeBuf for #ident { + unsafe impl #path::Size for #ident { const SIZE: usize = #size; } - impl #ident { - /// Serialize into the serialization medium. - pub fn serialize_buf<'a>( - &self, - buf: &'a mut <#path::encoding::Vanilla as #path::Encoding>::Serialized<{ ::SIZE }>, - ) -> usize where - &'a mut <#path::encoding::Vanilla as #path::Encoding>::Serialized<{ ::SIZE }>: - IntoIterator::Word> + 'a, - { - unsafe { #path::SerializeIter::serialize_iter(self, buf).unwrap_unchecked() } - } - - /// Deserialize from the serialization medium. - pub fn deserialize_buf<'a>(src: &'a <#path::encoding::Vanilla as #path::Encoding>::Serialized<{ ::SIZE }>) -> Result - where - &'a <#path::encoding::Vanilla as #path::Encoding>::Serialized<{ ::SIZE }>: - IntoIterator::Word> + 'a, - { - #path::SerializeIter::deserialize_iter(src).or_else(|err| match err { - #path::error::Error::Invalid => Err(#path::error::Invalid), - // SAFETY: dependent on safety of trait implementation. - // `Serialized` must be of sufficient length. - #path::error::Error::EndOfInput => unsafe { ::core::hint::unreachable_unchecked() }, - }) - } - } + impl #path::SerializeBuf<{ <#ident as #path::Size>::SIZE }> for #ident {} } .into() } diff --git a/serac/Cargo.toml b/serac/Cargo.toml index cbd61ed..a917ec9 100644 --- a/serac/Cargo.toml +++ b/serac/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "serac" -version = "0.2.1" +version = "0.3.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.2.0" } +macros = { package = "embedded-command-macros", version = "0.3.0" } fill-array = "0.2.1" # for binary diff --git a/serac/src/bin/asm.rs b/serac/src/bin/asm.rs index a4f3cab..ed00c57 100644 --- a/serac/src/bin/asm.rs +++ b/serac/src/bin/asm.rs @@ -5,8 +5,8 @@ use core::ptr::{null, null_mut, read_volatile, write_volatile}; use panic_halt as _; -use cookie_cutter::{encoding::vanilla, SerializeIter}; use cortex_m_rt::entry; +use serac::{SerializeIter, encoding::vanilla}; #[derive(vanilla::SerializeIter)] struct Foo { @@ -21,7 +21,7 @@ fn deserialize(buf: &[u8; N]) -> Foo { #[inline(never)] fn serialize(foo: Foo, buf: &mut [u8; N]) { - unsafe { foo.serialize_iter(buf).unwrap_unchecked() } + unsafe { foo.serialize_iter(buf).unwrap_unchecked() }; } #[entry] diff --git a/serac/src/encoding/vanilla.rs b/serac/src/encoding/vanilla.rs index 95aaa41..e63ecce 100644 --- a/serac/src/encoding/vanilla.rs +++ b/serac/src/encoding/vanilla.rs @@ -4,7 +4,7 @@ use fill_array::fill; use super::Encoding; -use crate::{Medium, SerializeBuf, SerializeIter, error}; +use crate::{Medium, SerializeBuf, SerializeIter, Size, error}; // reexport proc macros pub use macros::{SerializeBuf, SerializeIter}; @@ -62,9 +62,11 @@ macro_rules! impl_number { } // SAFETY: $SIZE must be correct as it is validated by it's usage with `from_le_bytes` - unsafe impl SerializeBuf for $TYPE { + unsafe impl Size for $TYPE { const SIZE: usize = $SIZE; } + + impl SerializeBuf<{ <$TYPE as Size>::SIZE }> for $TYPE {} }; } @@ -117,7 +119,7 @@ impl SerializeIter for bool { } } -unsafe impl SerializeBuf for bool { +unsafe impl Size for bool { const SIZE: usize = 1; } @@ -164,7 +166,7 @@ impl SerializeIter for [T; N] { // implementing `SerializeBuf` for generic arrays requires the "generic_const_exprs" feature -unsafe impl SerializeBuf for [T; N] { +unsafe impl Size for [T; N] { const SIZE: usize = T::SIZE * N; } @@ -208,7 +210,7 @@ macro_rules! impl_tuple { } } - unsafe impl<$($TYPE: SerializeBuf),+> SerializeBuf for ($($TYPE,)+) { + unsafe impl<$($TYPE: Size),+> Size for ($($TYPE,)+) { const SIZE: usize = $($TYPE::SIZE+)+0; } }; @@ -481,7 +483,7 @@ mod tests { #[derive(Debug, PartialEq, vanilla::SerializeIter)] struct BarGen where - T: SerializeIter + SerializeBuf, + T: SerializeIter, { a: T, b: FooGen, diff --git a/serac/src/lib.rs b/serac/src/lib.rs index bf70b52..aa15279 100644 --- a/serac/src/lib.rs +++ b/serac/src/lib.rs @@ -76,15 +76,38 @@ pub trait SerializeIter: Sized { /// exact length. This length being the minimum needed for any value of the /// implementer type. /// -/// To implement this trait, the type must already implement `SerializeIter` and the -/// implementer must compute the necessary length of the serialization medium. +/// To implement this trait, the type must already implement [`SerializeIter`] and [`Size`]. +pub trait SerializeBuf: SerializeIter + Size { + fn serialize_buf<'a>(&self, buf: &'a mut E::Serialized) -> usize + where + &'a mut E::Serialized: IntoIterator, + E::Word: 'a, + { + unsafe { SerializeIter::serialize_iter(self, buf).unwrap_unchecked() } + } + + fn deserialize_buf<'a>(src: &'a E::Serialized) -> Result + where + &'a E::Serialized: IntoIterator, + E::Word: 'a, + { + SerializeIter::deserialize_iter(src).or_else(|err| match err { + error::Error::Invalid => Err(error::Invalid), + // SAFETY: dependent on safety of trait implementation. + // `Serialized` must be of sufficient length. + error::Error::EndOfInput => unsafe { ::core::hint::unreachable_unchecked() }, + }) + } +} + +/// This trait allows implementors to define the serialized size according to the encoding scheme. /// /// # Safety /// /// The value of the associated `SIZE` constant is critical. An insufficient size /// *will* result in UB. Best to leave this implementation to the procedural macro. -pub unsafe trait SerializeBuf: SerializeIter { - /// The size of the implementor when serialized, according to the encoding +pub unsafe trait Size { + // The size of the implementor when serialized, according to the encoding /// scheme. const SIZE: usize; } @@ -95,7 +118,7 @@ pub unsafe trait SerializeBuf: SerializeIter { #[macro_export] macro_rules! buf { ($ty:ty: $enc:ty $(, $coef:expr)?) => { - <<$enc as serac::Encoding>::Serialized<{ <$ty as serac::SerializeBuf>::SIZE $(*$coef)? }> as serac::Medium>::default() + <<$enc as serac::Encoding>::Serialized<{ <$ty as serac::Size>::SIZE $(*$coef)? }> as serac::Medium>::default() }; ($ty:ty $(, $coef:expr)?) => { buf!($ty: serac::encoding::Vanilla $(, $coef)?)