Skip to content

Commit

Permalink
Improve support for embedded targets (#69)
Browse files Browse the repository at this point in the history
* ci: test building on embedded targets
* Set resolver=2 in the workspace
* ci: test with feature serde but no alloc
* derive: Manually impl Serialize for PacketSerializer
to avoid the serde feature requiring alloc
  • Loading branch information
mattico authored Sep 27, 2023
1 parent 8f3e5e2 commit 32e4a17
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 21 deletions.
29 changes: 21 additions & 8 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ jobs:
feature-args:
- ''
- --no-default-features --features alloc
- --no-default-features --features serde
- --no-default-features
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install libudev
run: sudo apt-get update && sudo apt-get install -y libudev-dev
- name: Install MSRV
Expand All @@ -34,17 +35,29 @@ jobs:
run: |
cargo fmt --all -- --check
cargo clippy --all-features --all-targets -- -D warnings
- name: Examples - build
run: cd ${{ github.workspace }} && cargo build
- name: Examples - coding style
run: |
cd ${{ github.workspace }} && cargo fmt --all -- --check
cd ${{ github.workspace }} && cargo clippy --all-features --all-targets -- -D warnings
build_embedded:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install MSRV
uses: actions-rs/toolchain@v1
with:
toolchain: 1.70.0
override: true
- name: Install embedded targets
run: rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabihf
- name: Build
run: cargo build --verbose --no-default-features --target thumbv6m-none-eabi --target thumbv7m-none-eabi --target thumbv7em-none-eabihf
- name: Build (alloc)
run: cargo build --verbose --no-default-features --target thumbv6m-none-eabi --target thumbv7m-none-eabi --target thumbv7em-none-eabihf --features alloc
- name: Build (serde)
run: cargo build --verbose --no-default-features --target thumbv6m-none-eabi --target thumbv7m-none-eabi --target thumbv7em-none-eabihf --features serde

build_examples:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install libudev
run: sudo apt-get update && sudo apt-get install -y libudev-dev
- name: Install MSRV
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[workspace]
members = ["ublox", "ublox_derive"]
resolver = "2"
9 changes: 9 additions & 0 deletions ublox/src/ubx_packets/packets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ use super::{
UbxUnknownPacketRef, SYNC_CHAR_1, SYNC_CHAR_2,
};

/// Used to help serialize the packet's fields flattened within a struct containing the msg_id and class fields, but
/// without using the serde FlatMapSerializer which requires alloc.
#[cfg(feature = "serde")]
pub(crate) trait SerializeUbxPacketFields {
fn serialize_fields<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where
S: serde::ser::SerializeMap;
}

/// Geodetic Position Solution
#[ubx_packet_recv]
#[ubx(class = 1, id = 2, fixed_payload_len = 28)]
Expand Down
30 changes: 27 additions & 3 deletions ublox_derive/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,25 @@ fn generate_serialize_impl(
}
});
quote! {
#[cfg(feature = "serde")]
impl SerializeUbxPacketFields for #ref_name<'_> {
fn serialize_fields<S>(&self, state: &mut S) -> Result<(), S::Error>
where
S: serde::ser::SerializeMap,
{
#(#fields)*
Ok(())
}
}

#[cfg(feature = "serde")]
impl serde::Serialize for #ref_name<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(None)?;
#(#fields)*
self.serialize_fields(&mut state)?;
state.end()
}
}
Expand Down Expand Up @@ -776,14 +787,27 @@ pub fn generate_code_for_parse(recv_packs: &RecvPackets) -> TokenStream {
[a, b][(a < b) as usize]
}
pub(crate) const MAX_PAYLOAD_LEN: u16 = #max_payload_len_calc;
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg(feature = "serde")]
pub struct PacketSerializer<'a, T> {
class: u8,
msg_id: u8,
#[cfg_attr(feature = "serde", serde(flatten))]
msg: &'a T,
}

#[cfg(feature = "serde")]
impl<'a, T: SerializeUbxPacketFields> serde::Serialize for PacketSerializer<'a, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry("class", &self.class)?;
state.serialize_entry("msg_id", &self.msg_id)?;
self.msg.serialize_fields(&mut state)?;
state.end()
}
}

#[cfg(feature = "serde")]
impl serde::Serialize for #union_enum_name<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand Down
53 changes: 43 additions & 10 deletions ublox_derive/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,18 +172,28 @@ fn test_ubx_packet_recv_simple() {
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for TestRef<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
impl SerializeUbxPacketFields for TestRef<'_> {
fn serialize_fields<S>(&self, state: &mut S) -> Result<(), S::Error>
where
S: serde::Serializer,
S: serde::ser::SerializeMap,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry(stringify!(itow), &self.itow())?;
state.serialize_entry(stringify!(lat), &self.lat_degrees())?;
state.serialize_entry(stringify!(a), &self.a())?;
state.serialize_entry(stringify!(reserved1), &self.reserved1())?;
state.serialize_entry(stringify!(flags), &self.flags())?;
state.serialize_entry(stringify!(b), &self.b())?;
Ok(())
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for TestRef<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(None)?;
self.serialize_fields(&mut state)?;
state.end()
}
}
Expand Down Expand Up @@ -280,17 +290,27 @@ fn test_ubx_packet_recv_dyn_len() {
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for TestRef<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
impl SerializeUbxPacketFields for TestRef<'_> {
fn serialize_fields<S>(&self, state: &mut S) -> Result<(), S::Error>
where
S: serde::Serializer,
S: serde::ser::SerializeMap,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry(stringify!(f1), &self.f1())?;
state.serialize_entry(
stringify!(rest),
&crate::ubx_packets::FieldIter(self.rest()),
)?;
Ok(())
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for TestRef<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(None)?;
self.serialize_fields(&mut state)?;
state.end()
}
}
Expand Down Expand Up @@ -556,14 +576,27 @@ fn test_define_recv_packets() {
max_u16(Pack1::MAX_PAYLOAD_LEN, 0u16),
);

#[cfg_attr(feature = "serde", derive(serde :: Serialize))]
#[cfg(feature = "serde")]
pub struct PacketSerializer<'a, T> {
class: u8,
msg_id: u8,
#[cfg_attr(feature = "serde", serde(flatten))]
msg: &'a T,
}

#[cfg(feature = "serde")]
impl<'a, T: SerializeUbxPacketFields> serde::Serialize for PacketSerializer<'a, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_map(None)?;
state.serialize_entry("class", &self.class)?;
state.serialize_entry("msg_id", &self.msg_id)?;
self.msg.serialize_fields(&mut state)?;
state.end()
}
}

#[cfg(feature = "serde")]
impl serde::Serialize for PacketRef<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand Down

0 comments on commit 32e4a17

Please sign in to comment.