
# Background In `no_std` compatible crates, there is often an `std` feature which will allow access to the standard library. Currently, with the `std` feature _enabled_, the [`std::prelude`](https://doc.rust-lang.org/std/prelude/index.html) is implicitly imported in all modules. With the feature _disabled_, instead the [`core::prelude`](https://doc.rust-lang.org/core/prelude/index.html) is implicitly imported. This creates a subtle and pervasive issue where `alloc` items _may_ be implicitly included (if `std` is enabled), or must be explicitly included (if `std` is not enabled). # Objective - Make the implicit imports for `no_std` crates consistent regardless of what features are/not enabled. ## Solution - Replace the `cfg_attr` "double negative" `no_std` attribute with conditional compilation to _include_ `std` as an external crate. ```rust // Before #![cfg_attr(not(feature = "std"), no_std)] // After #![no_std] #[cfg(feature = "std")] extern crate std; ``` - Fix imports that are currently broken but are only now visible with the above fix. ## Testing - CI ## Notes I had previously used the "double negative" version of `no_std` based on general consensus that it was "cleaner" within the Rust embedded community. However, this implicit prelude issue likely was considered when forming this consensus. I believe the reason why is the items most affected by this issue are provided by the `alloc` crate, which is rarely used within embedded but extensively used within Bevy.
113 lines
2.8 KiB
Rust
113 lines
2.8 KiB
Rust
/// Helper macro to implement the necessary traits for function reflection.
|
|
///
|
|
/// This macro calls the following macros:
|
|
/// - [`impl_get_ownership`](crate::func::args::impl_get_ownership)
|
|
/// - [`impl_from_arg`](crate::func::args::impl_from_arg)
|
|
/// - [`impl_into_return`](crate::func::impl_into_return)
|
|
///
|
|
/// # Syntax
|
|
///
|
|
/// For non-generic types, the macro simply expects the type:
|
|
///
|
|
/// ```ignore
|
|
/// impl_function_traits!(foo::bar::Baz);
|
|
/// ```
|
|
///
|
|
/// For generic types, however, the generic type parameters must also be given in angle brackets (`<` and `>`):
|
|
///
|
|
/// ```ignore
|
|
/// impl_function_traits!(foo::bar::Baz<T, U>; <T: Clone, U>);
|
|
/// ```
|
|
///
|
|
/// For generic const parameters, they must be given in square brackets (`[` and `]`):
|
|
///
|
|
/// ```ignore
|
|
/// impl_function_traits!(foo::bar::Baz<T, N>; <T> [const N: usize]);
|
|
/// ```
|
|
macro_rules! impl_function_traits {
|
|
(
|
|
$ty: ty
|
|
$(;
|
|
<
|
|
$($T: ident $(: $T1: tt $(+ $T2: tt)*)?),*
|
|
>
|
|
)?
|
|
$(
|
|
[
|
|
$(const $N: ident : $size: ident),*
|
|
]
|
|
)?
|
|
$(
|
|
where
|
|
$($U: ty $(: $U1: tt $(+ $U2: tt)*)?),*
|
|
)?
|
|
) => {
|
|
$crate::func::args::impl_get_ownership!(
|
|
$ty
|
|
$(;
|
|
<
|
|
$($T $(: $T1 $(+ $T2)*)?),*
|
|
>
|
|
)?
|
|
$(
|
|
[
|
|
$(const $N : $size),*
|
|
]
|
|
)?
|
|
$(
|
|
where
|
|
$($U $(: $U1 $(+ $U2)*)?),*
|
|
)?
|
|
);
|
|
$crate::func::args::impl_from_arg!(
|
|
$ty
|
|
$(;
|
|
<
|
|
$($T $(: $T1 $(+ $T2)*)?),*
|
|
>
|
|
)?
|
|
$(
|
|
[
|
|
$(const $N : $size),*
|
|
]
|
|
)?
|
|
$(
|
|
where
|
|
$($U $(: $U1 $(+ $U2)*)?),*
|
|
)?
|
|
);
|
|
$crate::func::impl_into_return!(
|
|
$ty
|
|
$(;
|
|
<
|
|
$($T $(: $T1 $(+ $T2)*)?),*
|
|
>
|
|
)?
|
|
$(
|
|
[
|
|
$(const $N : $size),*
|
|
]
|
|
)?
|
|
$(
|
|
where
|
|
$($U $(: $U1 $(+ $U2)*)?),*
|
|
)?
|
|
);
|
|
};
|
|
}
|
|
|
|
pub(crate) use impl_function_traits;
|
|
|
|
/// Helper macro that returns the number of tokens it receives.
|
|
///
|
|
/// See [here] for details.
|
|
///
|
|
/// [here]: https://veykril.github.io/tlborm/decl-macros/building-blocks/counting.html#bit-twiddling
|
|
macro_rules! count_tokens {
|
|
() => { 0 };
|
|
($odd:tt $($a:tt $b:tt)*) => { ($crate::func::macros::count_tokens!($($a)*) << 1) | 1 };
|
|
($($a:tt $even:tt)*) => { $crate::func::macros::count_tokens!($($a)*) << 1 };
|
|
}
|
|
|
|
pub(crate) use count_tokens;
|