Skip to content

Commit

Permalink
Add one-of crate for mutually exclusive features (#625)
Browse files Browse the repository at this point in the history
  • Loading branch information
ia0 authored Sep 30, 2024
1 parent e052860 commit 777002b
Show file tree
Hide file tree
Showing 89 changed files with 558 additions and 8 deletions.
1 change: 1 addition & 0 deletions crates/api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

### Patch

- Make sure at compile-time that exactly one `host` or `wasm` feature is enabled
- Update dependencies

## 0.6.1
Expand Down
5 changes: 5 additions & 0 deletions crates/api/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ sealed = { version = "0.5.0", default-features = false, optional = true }
wasefire-applet-api-macro = { version = "0.7.0-git", path = "../api-macro" }
wasefire-error = { version = "0.1.2-git", path = "../error" }
wasefire-logger = { version = "0.1.5", path = "../logger", optional = true }
wasefire-one-of = { version = "0.1.0-git", path = "../one-of" }

[features]
# Compiles for host or wasm (choose exactly one).
Expand Down
3 changes: 3 additions & 0 deletions crates/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ extern crate alloc;
#[cfg(feature = "host")]
pub use host::*;
use wasefire_error as _;
use wasefire_one_of::exactly_one_of;

#[cfg(feature = "host")]
mod host;
#[cfg(feature = "wasm")]
pub(crate) mod wasm;

exactly_one_of!["host", "wasm"];

#[cfg(feature = "wasm")]
wasefire_applet_api_macro::wasm!();

Expand Down
5 changes: 5 additions & 0 deletions crates/board/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions crates/cli-tools/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions crates/cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/one-of/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

## 0.1.0-git

<!-- Increment to skip CHANGELOG.md test: 0 -->
7 changes: 7 additions & 0 deletions crates/one-of/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions crates/one-of/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "wasefire-one-of"
version = "0.1.0-git"
authors = ["Julien Cretin <cretin@google.com>"]
license = "Apache-2.0"
publish = true
edition = "2021"
description = "Macros for mutually exclusive features"
repository = "https://github.com/google/wasefire"
include = ["/LICENSE", "/src/"]
keywords = ["macro", "no-std"]
categories = ["no-std"]

[lints]
clippy.unit-arg = "allow"
rust.missing-docs = "warn"
rust.unreachable-pub = "warn"
rust.unsafe-op-in-unsafe-fn = "warn"
rust.unused-crate-dependencies = "warn"
1 change: 1 addition & 0 deletions crates/one-of/LICENSE
91 changes: 91 additions & 0 deletions crates/one-of/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Provides macros to check mutually exclusive features.

#![no_std]

// TODO(https://github.com/rust-lang/rust/issues/122105): Remove when fixed.
extern crate alloc;

/// Makes sure exactly one of the provided feature is enabled.
///
/// For example, `exactly_one_of!["a", "b", "c"]` will expand to:
///
/// ```ignore
/// #[cfg(any(
/// not(any(feature = "a", feature = "b", feature = "c")),
/// all(feature = "a", feature = "b"),
/// all(feature = "a", feature = "c"),
/// all(feature = "b", feature = "c"),
/// ))]
/// compile_error!("Exactly one of feature \"a\", \"b\", or \"c\" can be enabled.");
/// ```
#[macro_export]
macro_rules! exactly_one_of {
($f:literal, $($fs:literal),+$(,)?) => {
$crate::internal_one_of!(0 [$f $($fs)*] "Exactly");
};
}

/// Makes sure at most one of the provided feature is enabled.
///
/// For example, `at_most_one_of!["a", "b", "c"]` will expand to:
///
/// ```ignore
/// #[cfg(any(
/// all(feature = "a", feature = "b"),
/// all(feature = "a", feature = "c"),
/// all(feature = "b", feature = "c"),
/// ))]
/// compile_error!("At most one of feature \"a\", \"b\", or \"c\" can be enabled.");
/// ```
#[macro_export]
macro_rules! at_most_one_of {
($f:literal, $($fs:literal),+$(,)?) => {
$crate::internal_one_of!(1 [$f $($fs)*] () ["At most";]);
};
}

#[doc(hidden)]
#[macro_export]
macro_rules! internal_one_of {
(0 [$($f:literal)*] $p:literal) => {
$crate::internal_one_of!(1 [$($f)*] (not(any($(feature = $f),*)),) [$p;]);
};

(1 [$f:literal $($fs:literal)*] $r:tt [$($ds:literal)*; $($d:literal)?]) => {
$crate::internal_one_of!(2 [$($fs)*] $f [$($fs)*] $r [$($ds)* $($d)?; $f]);
};
(1 [] $r:tt $ds:tt) => {
#[cfg(any $r)]
$crate::internal_one_of!(3 $ds);
};

(2 $s:tt $g:literal [$f:literal $($fs:literal)*] ($($r:tt)*) $d:tt) => {
$crate::internal_one_of!(2 $s $g [$($fs)*] ($($r)* all(feature = $g, feature = $f),) $d);
};
(2 $s:tt $g:literal [] $r:tt $d:tt) => {
$crate::internal_one_of!(1 $s $r $d);
};

(3 [$p:literal $a:literal; $b:literal]) => {
compile_error!(concat!($p, " one of feature ", stringify!($a), " or ", stringify!($b),
" can be enabled."));
};
(3 [$p:literal $($as:literal)*; $b:literal]) => {
compile_error!(concat!($p, " one of feature ",$(stringify!($as), ", ",)* "or ",
stringify!($b), " can be enabled."));
};
}
23 changes: 23 additions & 0 deletions crates/one-of/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -e

. "$(git rev-parse --show-toplevel)"/scripts/test-helper.sh

test_helper

cargo test --lib
cargo check --lib --target=thumbv7em-none-eabi
1 change: 1 addition & 0 deletions crates/prelude/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

### Patch

- Make sure at compile-time that at most one `native`, `test`, or `wasm` feature is enabled
- Update dependencies

## 0.6.0
Expand Down
6 changes: 6 additions & 0 deletions crates/prelude/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/prelude/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sealed = { version = "0.5.0", default-features = false, optional = true }
typenum = { version = "1.17.0", default-features = false, optional = true }
wasefire-applet-api = { version = "0.7.0-git", path = "../api", features = ["wasm"] }
wasefire-error = { version = "0.1.2-git", path = "../error" }
wasefire-one-of = { version = "0.1.0-git", path = "../one-of" }
wasefire-sync = { version = "0.1.1", path = "../sync" }
zeroize = { version = "1.7.0", default-features = false, features = ["derive"], optional = true }

Expand Down
3 changes: 3 additions & 0 deletions crates/prelude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ extern crate alloc;

use wasefire_applet_api as api;
pub use wasefire_error::Error;
use wasefire_one_of::at_most_one_of;
#[cfg(feature = "rust-crypto")]
use {aead as _, crypto_common as _, digest as _, typenum as _, zeroize as _};

Expand Down Expand Up @@ -77,6 +78,8 @@ pub mod uart;
#[cfg(feature = "internal-api-usb")]
pub mod usb;

at_most_one_of!["native", "test", "wasm"];

/// Board-specific syscalls.
///
/// Those calls are directly forwarded to the board by the scheduler.
Expand Down
2 changes: 1 addition & 1 deletion crates/protocol-tokio/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

## 0.1.0-git

<!-- Increment to skip CHANGELOG.md test: 5 -->
<!-- Increment to skip CHANGELOG.md test: 6 -->
5 changes: 5 additions & 0 deletions crates/protocol-tokio/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/protocol-tokio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ features = ["device"]
anyhow = { version = "1.0.86", default-features = false, features = ["std"] }
wasefire-error = { version = "0.1.2-git", path = "../error", optional = true }
wasefire-logger = { version = "0.1.5", path = "../logger" }
wasefire-one-of = { version = "0.1.0-git", path = "../one-of" }

[dependencies.tokio]
version = "1.40.0"
Expand Down
3 changes: 3 additions & 0 deletions crates/protocol-tokio/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
pub use device::*;
#[cfg(feature = "host")]
pub use host::*;
use wasefire_one_of::exactly_one_of;

mod common;
#[cfg(feature = "device")]
mod device;
#[cfg(feature = "host")]
mod host;

exactly_one_of!["device", "host"];
2 changes: 1 addition & 1 deletion crates/protocol-usb/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@

## 0.1.0

<!-- Increment to skip CHANGELOG.md test: 4 -->
<!-- Increment to skip CHANGELOG.md test: 5 -->
Loading

0 comments on commit 777002b

Please sign in to comment.