Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for alloc::vec::Vec #24

Merged
merged 1 commit into from
Nov 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ jobs:
fail-fast: false
matrix:
rust: [1.62.0, stable]
features: ['', '--all-features']
features: ['use_alloc', 'use_alloc,defmt', 'use_heapless', 'use_heapless,defmt']
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -21,15 +21,15 @@ jobs:
toolchain: ${{ matrix.rust }}
components: rustfmt clippy
- name: build
run: cargo build ${{ matrix.features }}
run: cargo build --features ${{ matrix.features }}
- name: check
run: cargo check ${{ matrix.features }}
run: cargo check --features ${{ matrix.features }}
- name: test
run: cargo test ${{ matrix.features }}
run: cargo test --features ${{ matrix.features }}
- name: check formatting
run: cargo fmt --all -- --check
- name: clippy
run: cargo clippy ${{ matrix.features }}
run: cargo clippy --features ${{ matrix.features }}
- name: audit
run: cargo audit

5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,9 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- next-header -->
## [Unreleased] - ReleaseDate
### Added
* Add support for using [`alloc::vec::Vec`](https://doc.rust-lang.org/alloc/vec/struct.Vec.html)
### Changed
* Due to dependency updates the MSRV has been updated from 1.60 to 1.62. This should only be relevant if you use the `defmt` feature, but we now only test with 1.62 and not older releases, so it's not guaranteed to work otherwise.
* Update to `heapless:0.8.0`
### Breaking Changes
* You must now select either the feature `use_alloc` or `use_heapless` for the crate to compile. Select `use_heapless`
to keep the API from the previous release of this crate.

## [0.1.1] - 2023-01-07
### Changed
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -12,15 +12,18 @@ license = "MIT OR Apache-2.0"

[dependencies]
defmt = { version = "0.3", optional = true }
heapless = { version = "0.8" }
heapless = { version = "0.8", optional = true }

rgb = { version = "0.8", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }

[features]
default = ["accelerometer_event", "button_event", "color_event", "gyro_event", "location_event", "magnetometer_event", "quaternion_event"]

defmt = ["dep:defmt", "heapless/defmt-03"]
use_heapless = ["dep:heapless"]
use_alloc = []

defmt = ["dep:defmt", "heapless?/defmt-03"]

accelerometer_event = []
button_event = []
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -9,7 +9,13 @@ which is e.g. used by the [Adafruit Bluefruit LE UART Friend](https://learn.adaf

Note that this work is not affiliated with Adafruit.

## Optional features
## Mandatory Features
This crate is `no_std` and you can choose whether you want to use
[`heapless::Vec`](https://docs.rs/heapless/0.8.0/heapless/struct.Vec.html) by selecting the feature `use_heapless` or
[`alloc::vec::Vec`](https://doc.rust-lang.org/alloc/vec/struct.Vec.html) by selecting the feature `use_alloc`.
If you select neither or both you'll get a compile error.

## Optional Features
* `defmt`: you can enable the [`defmt`](https://defmt.ferrous-systems.com/) feature to get a `defmt::Format` implementation for all structs & enums and a `defmt::debug!` call for each command being parsed.
* `rgb`: if enabled, `From<ColorEvent> for RGB8` is implemented to support the [RGB crate](https://crates.io/crates/rgb).
* `serde`: if enabled, all events implement the [serde](https://serde.rs/) `#[derive(Serialize, Deserialize)]`.
2 changes: 1 addition & 1 deletion examples/stm32f4-event-printer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ defmt = "0.3.5"
defmt-rtt = "0.4"

# use `adafruit-bluefruit-protocol = "0.1"` in reality; path used here to ensure that the example always compiles against the latest master
adafruit-bluefruit-protocol = { path = "../..", features = ["defmt"] }
adafruit-bluefruit-protocol = { path = "../..", features = ["defmt", "use_heapless"] }

[profile.release]
codegen-units = 1
37 changes: 32 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -29,6 +29,12 @@
)))]
compile_error!("at least one event type must be selected in the features!");

#[cfg(not(any(feature = "use_alloc", feature = "use_heapless")))]
compile_error!("you must choose either 'use_alloc' or 'use_heapless' as a feature!");

#[cfg(all(feature = "use_alloc", feature = "use_heapless"))]
compile_error!("you must choose either 'use_alloc' or 'use_heapless' as a feature but not both!");

#[cfg(feature = "accelerometer_event")]
pub mod accelerometer_event;
#[cfg(feature = "button_event")]
@@ -53,7 +59,13 @@ use color_event::ColorEvent;
use core::cmp::min;
#[cfg(feature = "gyro_event")]
use gyro_event::GyroEvent;
#[cfg(feature = "use_heapless")]
use heapless::Vec;

#[cfg(feature = "use_alloc")]
extern crate alloc;
#[cfg(feature = "use_alloc")]
use alloc::vec::Vec;
#[cfg(feature = "location_event")]
use location_event::LocationEvent;
#[cfg(feature = "magnetometer_event")]
@@ -156,18 +168,27 @@ impl TryFrom<u8> for ControllerDataPackageType {
}
}

#[cfg(feature = "use_heapless")]
type ParseResult<const MAX_RESULTS: usize> =
Vec<Result<ControllerEvent, ProtocolParseError>, MAX_RESULTS>;

#[cfg(feature = "use_alloc")]
type ParseResult<const MAX_RESULTS: usize> = Vec<Result<ControllerEvent, ProtocolParseError>>;
#[cfg(feature = "use_alloc")]
const MAX_RESULTS: usize = 0;

/// Parse the input string for commands. Unexpected content will be ignored if it's not formatted like a command!
pub fn parse<const MAX_RESULTS: usize>(
pub fn parse<#[cfg(feature = "use_heapless")] const MAX_RESULTS: usize>(
input: &[u8],
) -> Vec<Result<ControllerEvent, ProtocolParseError>, MAX_RESULTS> {
) -> ParseResult<MAX_RESULTS> {
/// Simple state machine for the parser, represents whether the parser is seeking a start or has found it.
enum ParserState {
SeekStart,
ParseCommand,
}
let mut state = ParserState::SeekStart;

let mut result: Vec<Result<ControllerEvent, ProtocolParseError>, MAX_RESULTS> = Vec::new();
let mut result = Vec::new();

for pos in 0..input.len() {
let byte = input[pos];
@@ -179,7 +200,11 @@ pub fn parse<const MAX_RESULTS: usize>(
}
ParserState::ParseCommand => {
let data_package = extract_and_parse_command(&input[(pos - 1)..]);
#[cfg(feature = "use_alloc")]
result.push(data_package);
#[cfg(feature = "use_heapless")]
result.push(data_package).ok();
#[cfg(feature = "use_heapless")]
if result.len() == MAX_RESULTS {
return result;
}
@@ -334,9 +359,11 @@ mod tests {

#[test]
fn test_parse() {
const MAX_RESULTS: usize = 4;
let input = b"\x00!B11:!B10;\x00\x00!\x00\x00\x00\x00";
let result = parse::<MAX_RESULTS>(input);
#[cfg(feature = "use_heapless")]
let result = parse::<4>(input);
#[cfg(feature = "use_alloc")]
let result = parse(input);

assert_eq!(result.len(), 3);
assert_is_button_event(&result[0], Button::Button1, ButtonState::Pressed);