Skip to content

Commit

Permalink
Merge pull request #24 from rursprung/add-support-for-alloc
Browse files Browse the repository at this point in the history
add support for `alloc::vec::Vec`
  • Loading branch information
rursprung authored Nov 14, 2023
2 parents d745ca6 + b12d67d commit 52bd0be
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 14 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)]`.
Expand Down
2 changes: 1 addition & 1 deletion examples/stm32f4-event-printer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 32 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand All @@ -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")]
Expand Down Expand Up @@ -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];
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 52bd0be

Please sign in to comment.