mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-10-02 14:54:30 +00:00
Merge #43
43: Put all const functions behind a const-fn feature r=japaric a=XOSplicer ## Purpose This PR introduces the `const-fn` feature gate, which when enabled makes most `new` methods `const` and therefore usable for initializing `static` variables. The idea was introduced in #40 with the purpose to come closer to targeting stable rust. `const` functions are currently only available on rust nightly (tracking issue: [const fn tracking issue (RFC 911)](https://github.com/rust-lang/rust/issues/24111)). In order to target stable rust this feature is made opt-in. This feature is a **breaking change** as users of the library now need to explicitly enable it by changing their `Cargo.toml`: ``` ... [dependencies] heapless = { version = "0.4.0", features = ["const-fn"] } ... ``` ## Approach The implementation of the feature mainly consist of the `const_fn!` macro, which takes a function with `const` modifier and removes the modifier if the feature gate is not activated. For the `const` functions a test is intoduced that checks if `static` variables can be initialized. These tests are only active if the feature is active. I have not found a way to make doc-test depend on a feature. Therefore some doc-tests are adapted, so that no static initialization is necessary. The `ci/script.sh` is adapted to also tests with the `--all-feature` flag ## Future When in the future the `const_fn` rust feature becomes stable, this feature gate **might become active by default**. Closes #41 . Co-authored-by: Felix <stegmaier.felix@gmail.com> Co-authored-by: Felix Stegmaier <stegmaier.felix@gmail.com> Co-authored-by: Felix Stegmaier <felix.stegmaier@hpe.com>
This commit is contained in:
commit
f1b58a8d67
@ -18,6 +18,10 @@ name = "heapless"
|
|||||||
repository = "https://github.com/japaric/heapless"
|
repository = "https://github.com/japaric/heapless"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["const-fn"]
|
||||||
|
const-fn = []
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
scoped_threadpool = "0.1.8"
|
scoped_threadpool = "0.1.8"
|
||||||
|
|
||||||
|
@ -5,14 +5,18 @@ main() {
|
|||||||
|
|
||||||
if [ $TARGET = x86_64-unknown-linux-gnu ]; then
|
if [ $TARGET = x86_64-unknown-linux-gnu ]; then
|
||||||
cargo test --target $TARGET
|
cargo test --target $TARGET
|
||||||
|
cargo test --target $TARGET --no-default-features
|
||||||
cargo test --target $TARGET --release
|
cargo test --target $TARGET --release
|
||||||
|
cargo test --target $TARGET --release --no-default-features
|
||||||
|
|
||||||
export RUSTFLAGS="-Z sanitizer=thread"
|
export RUSTFLAGS="-Z sanitizer=thread"
|
||||||
export RUST_TEST_THREADS=1
|
export RUST_TEST_THREADS=1
|
||||||
export TSAN_OPTIONS="suppressions=$(pwd)/blacklist.txt"
|
export TSAN_OPTIONS="suppressions=$(pwd)/blacklist.txt"
|
||||||
|
|
||||||
cargo test --test tsan --target $TARGET
|
cargo test --test tsan --target $TARGET
|
||||||
|
cargo test --test tsan --target $TARGET --no-default-features
|
||||||
cargo test --test tsan --target $TARGET --release
|
cargo test --test tsan --target $TARGET --release
|
||||||
|
cargo test --test tsan --target $TARGET --release --no-default-features
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,9 +12,11 @@ pub mod mem {
|
|||||||
|
|
||||||
impl<T> ManuallyDrop<T> {
|
impl<T> ManuallyDrop<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
const_fn!(
|
||||||
pub const fn new(value: T) -> ManuallyDrop<T> {
|
pub const fn new(value: T) -> ManuallyDrop<T> {
|
||||||
ManuallyDrop { value: value }
|
ManuallyDrop { value: value }
|
||||||
}
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for ManuallyDrop<T> {
|
impl<T> Deref for ManuallyDrop<T> {
|
||||||
@ -33,6 +35,7 @@ pub mod mem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const_fn!(
|
||||||
pub const unsafe fn uninitialized<T>() -> T {
|
pub const unsafe fn uninitialized<T>() -> T {
|
||||||
#[allow(unions_with_drop_fields)]
|
#[allow(unions_with_drop_fields)]
|
||||||
union U<T> {
|
union U<T> {
|
||||||
@ -42,4 +45,32 @@ pub mod mem {
|
|||||||
|
|
||||||
U { none: () }.some
|
U { none: () }.some
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")] // Remove this if there are more tests
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use __core;
|
||||||
|
use __core::mem::ManuallyDrop;
|
||||||
|
use core;
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
#[test]
|
||||||
|
fn static_uninitzialized() {
|
||||||
|
static mut I: i32 = unsafe { __core::mem::uninitialized() };
|
||||||
|
// Initialize before drop
|
||||||
|
unsafe { core::ptr::write(&mut I as *mut i32, 42) };
|
||||||
|
unsafe{ assert_eq!(I, 42) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
#[test]
|
||||||
|
fn static_new_manually_drop() {
|
||||||
|
static mut M: ManuallyDrop<i32> = ManuallyDrop::new(42);
|
||||||
|
unsafe { assert_eq!(*M, 42); }
|
||||||
|
// Drop before deinitialization
|
||||||
|
unsafe { core::ptr::drop_in_place(&mut M as &mut i32 as *mut i32) };
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,8 @@ where
|
|||||||
K: Kind,
|
K: Kind,
|
||||||
{
|
{
|
||||||
/* Constructors */
|
/* Constructors */
|
||||||
|
|
||||||
|
const_fn!(
|
||||||
/// Creates an empty BinaryHeap as a $K-heap.
|
/// Creates an empty BinaryHeap as a $K-heap.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -122,6 +124,7 @@ where
|
|||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/* Public API */
|
/* Public API */
|
||||||
/// Returns the capacity of the binary heap.
|
/// Returns the capacity of the binary heap.
|
||||||
@ -430,6 +433,12 @@ mod tests {
|
|||||||
use binary_heap::{self, BinaryHeap, Min};
|
use binary_heap::{self, BinaryHeap, Min};
|
||||||
use consts::*;
|
use consts::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
#[test]
|
||||||
|
fn static_new() {
|
||||||
|
static mut _B: BinaryHeap<i32, U16, Min> = BinaryHeap::new();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn min() {
|
fn min() {
|
||||||
let mut heap = BinaryHeap::<_, U16, Min>::new();
|
let mut heap = BinaryHeap::<_, U16, Min>::new();
|
||||||
|
35
src/const_fn.rs
Normal file
35
src/const_fn.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Make functions `const` if the `const-fn` feature is active.
|
||||||
|
// The meta attributes are in place to keep doc comments with the functions.
|
||||||
|
// The function definition incl. annotations and doc comments must be enclodes
|
||||||
|
// by the marco invocation.
|
||||||
|
macro_rules! const_fn {
|
||||||
|
($(#[$attr:meta])* pub const unsafe fn $($f:tt)*) => (
|
||||||
|
|
||||||
|
$(#[$attr])*
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
pub const unsafe fn $($f)*
|
||||||
|
|
||||||
|
$(#[$attr])*
|
||||||
|
#[cfg(not(feature = "const-fn"))]
|
||||||
|
pub unsafe fn $($f)*
|
||||||
|
);
|
||||||
|
($(#[$attr:meta])* pub const fn $($f:tt)*) => (
|
||||||
|
|
||||||
|
$(#[$attr])*
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
pub const fn $($f)*
|
||||||
|
|
||||||
|
$(#[$attr])*
|
||||||
|
#[cfg(not(feature = "const-fn"))]
|
||||||
|
pub fn $($f)*
|
||||||
|
);
|
||||||
|
($(#[$attr:meta])* const fn $($f:tt)*) => (
|
||||||
|
$(#[$attr])*
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
const fn $($f)*
|
||||||
|
|
||||||
|
$(#[$attr])*
|
||||||
|
#[cfg(not(feature = "const-fn"))]
|
||||||
|
fn $($f)*
|
||||||
|
);
|
||||||
|
}
|
38
src/lib.rs
38
src/lib.rs
@ -18,7 +18,15 @@
|
|||||||
//! assert_eq!(xs.pop(), Some(42));
|
//! assert_eq!(xs.pop(), Some(42));
|
||||||
//!
|
//!
|
||||||
//! // in a `static` variable
|
//! // in a `static` variable
|
||||||
//! static mut XS: Vec<u8, U8> = Vec::new();
|
//! // static mut XS: Vec<u8, U8> = Vec::new(); // requires feature `const-fn`
|
||||||
|
//!
|
||||||
|
//! // work around
|
||||||
|
//! static mut XS: Option<Vec<u8, U8>> = None;
|
||||||
|
//! unsafe { XS = Some(Vec::new()) };
|
||||||
|
//! let xs = unsafe { XS.as_mut().unwrap() };
|
||||||
|
//!
|
||||||
|
//! xs.push(42);
|
||||||
|
//! assert_eq!(xs.pop(), Some(42));
|
||||||
//!
|
//!
|
||||||
//! // in the heap (though kind of pointless because no reallocation)
|
//! // in the heap (though kind of pointless because no reallocation)
|
||||||
//! let mut ys: Box<Vec<u8, U8>> = Box::new(Vec::new());
|
//! let mut ys: Box<Vec<u8, U8>> = Box::new(Vec::new());
|
||||||
@ -47,11 +55,34 @@
|
|||||||
//! queue
|
//! queue
|
||||||
//! - [`String`](struct.String.html)
|
//! - [`String`](struct.String.html)
|
||||||
//! - [`Vec`](struct.Vec.html)
|
//! - [`Vec`](struct.Vec.html)
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! In order to target the Rust stable toolchain, there are some feature gates.
|
||||||
|
//! The features need to be enabled in `Cargo.toml` in order to use them.
|
||||||
|
//! Once the underlaying features in Rust are stable,
|
||||||
|
//! these feature gates might be activated by default.
|
||||||
|
//!
|
||||||
|
//! Example of `Cargo.toml`:
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! ...
|
||||||
|
//! [dependencies]
|
||||||
|
//! heapless = { version = "0.4.0", features = ["const-fn"] }
|
||||||
|
//! ...
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Currently the following features are availbale and not active by default:
|
||||||
|
//!
|
||||||
|
//! - `"const-fn"` -- Enable the nightly `const_fn` feature and make most `new` methods `const`.
|
||||||
|
//! This way they can be used to initialize static memory at compile time.
|
||||||
|
//!
|
||||||
|
|
||||||
|
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![feature(const_fn)]
|
#![cfg_attr(feature = "const-fn", feature(const_fn))]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(untagged_unions)]
|
#![feature(untagged_unions)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
@ -61,6 +92,9 @@ extern crate hash32;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod const_fn;
|
||||||
|
|
||||||
pub use binary_heap::BinaryHeap;
|
pub use binary_heap::BinaryHeap;
|
||||||
pub use generic_array::typenum::consts;
|
pub use generic_array::typenum::consts;
|
||||||
pub use generic_array::ArrayLength;
|
pub use generic_array::ArrayLength;
|
||||||
|
@ -21,6 +21,8 @@ where
|
|||||||
N: ArrayLength<(K, V)>,
|
N: ArrayLength<(K, V)>,
|
||||||
K: Eq,
|
K: Eq,
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const_fn!(
|
||||||
/// Creates an empty `LinearMap`
|
/// Creates an empty `LinearMap`
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -34,6 +36,7 @@ where
|
|||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
LinearMap { buffer: Vec::new() }
|
LinearMap { buffer: Vec::new() }
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/// Returns the number of elements that the map can hold
|
/// Returns the number of elements that the map can hold
|
||||||
///
|
///
|
||||||
@ -439,3 +442,18 @@ where
|
|||||||
self.iter.next().map(|&mut (ref k, ref mut v)| (k, v))
|
self.iter.next().map(|&mut (ref k, ref mut v)| (k, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")] // Remove this if there are more tests
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use consts::*;
|
||||||
|
use LinearMap;
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
#[test]
|
||||||
|
fn static_new() {
|
||||||
|
static mut _L: LinearMap<i32, i32, U8>= LinearMap::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -61,11 +61,13 @@ impl<U> Atomic<U>
|
|||||||
where
|
where
|
||||||
U: Uxx,
|
U: Uxx,
|
||||||
{
|
{
|
||||||
|
const_fn!(
|
||||||
const fn new(v: U) -> Atomic<U> {
|
const fn new(v: U) -> Atomic<U> {
|
||||||
Atomic {
|
Atomic {
|
||||||
v: UnsafeCell::new(v),
|
v: UnsafeCell::new(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
fn get_mut(&mut self) -> &mut U {
|
fn get_mut(&mut self) -> &mut U {
|
||||||
unsafe { &mut *self.v.get() }
|
unsafe { &mut *self.v.get() }
|
||||||
@ -116,13 +118,16 @@ where
|
|||||||
/// use heapless::RingBuffer;
|
/// use heapless::RingBuffer;
|
||||||
/// use heapless::consts::*;
|
/// use heapless::consts::*;
|
||||||
///
|
///
|
||||||
/// static mut RB: RingBuffer<Event, U4> = RingBuffer::new();
|
/// // static mut RB: RingBuffer<Event, U4> = RingBuffer::new(); // requires feature `const-fn`
|
||||||
|
///
|
||||||
|
/// static mut RB: Option<RingBuffer<Event, U4>> = None;
|
||||||
///
|
///
|
||||||
/// enum Event { A, B }
|
/// enum Event { A, B }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
|
/// unsafe { RB = Some(RingBuffer::new()) };
|
||||||
/// // NOTE(unsafe) beware of aliasing the `consumer` end point
|
/// // NOTE(unsafe) beware of aliasing the `consumer` end point
|
||||||
/// let mut consumer = unsafe { RB.split().1 };
|
/// let mut consumer = unsafe { RB.as_mut().unwrap().split().1 };
|
||||||
///
|
///
|
||||||
/// loop {
|
/// loop {
|
||||||
/// // `dequeue` is a lockless operation
|
/// // `dequeue` is a lockless operation
|
||||||
@ -138,7 +143,7 @@ where
|
|||||||
/// // this is a different execution context that can preempt `main`
|
/// // this is a different execution context that can preempt `main`
|
||||||
/// fn interrupt_handler() {
|
/// fn interrupt_handler() {
|
||||||
/// // NOTE(unsafe) beware of aliasing the `producer` end point
|
/// // NOTE(unsafe) beware of aliasing the `producer` end point
|
||||||
/// let mut producer = unsafe { RB.split().0 };
|
/// let mut producer = unsafe { RB.as_mut().unwrap().split().0 };
|
||||||
/// # let condition = true;
|
/// # let condition = true;
|
||||||
///
|
///
|
||||||
/// // ..
|
/// // ..
|
||||||
@ -264,6 +269,8 @@ macro_rules! impl_ {
|
|||||||
N: Add<U1> + Unsigned,
|
N: Add<U1> + Unsigned,
|
||||||
Sum<N, U1>: ArrayLength<T>,
|
Sum<N, U1>: ArrayLength<T>,
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const_fn!(
|
||||||
/// Creates an empty ring buffer with a fixed capacity of `N`
|
/// Creates an empty ring buffer with a fixed capacity of `N`
|
||||||
pub const fn $uxx() -> Self {
|
pub const fn $uxx() -> Self {
|
||||||
RingBuffer {
|
RingBuffer {
|
||||||
@ -272,6 +279,7 @@ macro_rules! impl_ {
|
|||||||
tail: Atomic::new(0),
|
tail: Atomic::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/// Returns the item in the front of the queue, or `None` if the queue is empty
|
/// Returns the item in the front of the queue, or `None` if the queue is empty
|
||||||
pub fn dequeue(&mut self) -> Option<T> {
|
pub fn dequeue(&mut self) -> Option<T> {
|
||||||
@ -349,10 +357,13 @@ where
|
|||||||
N: Add<U1> + Unsigned,
|
N: Add<U1> + Unsigned,
|
||||||
Sum<N, U1>: ArrayLength<T>,
|
Sum<N, U1>: ArrayLength<T>,
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const_fn!(
|
||||||
/// Alias for [`RingBuffer::usize`](struct.RingBuffer.html#method.usize)
|
/// Alias for [`RingBuffer::usize`](struct.RingBuffer.html#method.usize)
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
RingBuffer::usize()
|
RingBuffer::usize()
|
||||||
}
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_!(u8);
|
impl_!(u8);
|
||||||
@ -434,6 +445,12 @@ mod tests {
|
|||||||
use consts::*;
|
use consts::*;
|
||||||
use RingBuffer;
|
use RingBuffer;
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
#[test]
|
||||||
|
fn static_new() {
|
||||||
|
static mut _R: RingBuffer<i32, U4> = RingBuffer::new();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drop() {
|
fn drop() {
|
||||||
struct Droppable;
|
struct Droppable;
|
||||||
|
@ -207,9 +207,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sanity() {
|
fn sanity() {
|
||||||
static mut RB: RingBuffer<i32, U2> = RingBuffer::new();
|
let mut rb: RingBuffer<i32, U2> = RingBuffer::new();
|
||||||
|
|
||||||
let (mut p, mut c) = unsafe { RB.split() };
|
let (mut p, mut c) = rb.split();
|
||||||
|
|
||||||
assert_eq!(c.dequeue(), None);
|
assert_eq!(c.dequeue(), None);
|
||||||
|
|
||||||
|
@ -17,6 +17,9 @@ impl<N> String<N>
|
|||||||
where
|
where
|
||||||
N: ArrayLength<u8>,
|
N: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
const_fn!(
|
||||||
/// Constructs a new, empty `String` with a fixed capacity of `N`
|
/// Constructs a new, empty `String` with a fixed capacity of `N`
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -29,10 +32,10 @@ where
|
|||||||
///
|
///
|
||||||
/// let mut s: String<U4> = String::new();
|
/// let mut s: String<U4> = String::new();
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
String { vec: Vec::new() }
|
String { vec: Vec::new() }
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/// Converts a vector of bytes into a `String`.
|
/// Converts a vector of bytes into a `String`.
|
||||||
///
|
///
|
||||||
@ -521,6 +524,12 @@ mod tests {
|
|||||||
use consts::*;
|
use consts::*;
|
||||||
use {String, Vec};
|
use {String, Vec};
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
#[test]
|
||||||
|
fn static_new() {
|
||||||
|
static mut _S: String<U8> = String::new();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn debug() {
|
fn debug() {
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
@ -48,6 +48,7 @@ where
|
|||||||
N: ArrayLength<T>,
|
N: ArrayLength<T>,
|
||||||
{
|
{
|
||||||
/* Constructors */
|
/* Constructors */
|
||||||
|
const_fn!(
|
||||||
/// Constructs a new, empty vector with a fixed capacity of `N`
|
/// Constructs a new, empty vector with a fixed capacity of `N`
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Vec {
|
Vec {
|
||||||
@ -55,6 +56,7 @@ where
|
|||||||
len: 0,
|
len: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/* Public API */
|
/* Public API */
|
||||||
/// Returns the maximum number of elements the vector can hold
|
/// Returns the maximum number of elements the vector can hold
|
||||||
@ -512,6 +514,12 @@ mod tests {
|
|||||||
use consts::*;
|
use consts::*;
|
||||||
use Vec;
|
use Vec;
|
||||||
|
|
||||||
|
#[cfg(feature = "const-fn")]
|
||||||
|
#[test]
|
||||||
|
fn static_new() {
|
||||||
|
static mut _V: Vec<i32, U4> = Vec::new();
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! droppable {
|
macro_rules! droppable {
|
||||||
() => (
|
() => (
|
||||||
struct Droppable;
|
struct Droppable;
|
||||||
|
@ -13,9 +13,10 @@ use scoped_threadpool::Pool;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn once() {
|
fn once() {
|
||||||
static mut RB: RingBuffer<i32, U4> = RingBuffer::new();
|
static mut RB: Option<RingBuffer<i32, U4>> = None;
|
||||||
|
unsafe{ RB = Some(RingBuffer::new()) };
|
||||||
|
|
||||||
let rb = unsafe { &mut RB };
|
let rb = unsafe { RB.as_mut().unwrap() };
|
||||||
|
|
||||||
rb.enqueue(0).unwrap();
|
rb.enqueue(0).unwrap();
|
||||||
|
|
||||||
@ -34,9 +35,10 @@ fn once() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn twice() {
|
fn twice() {
|
||||||
static mut RB: RingBuffer<i32, U8> = RingBuffer::new();
|
static mut RB: Option<RingBuffer<i32, U4>> = None;
|
||||||
|
unsafe{ RB = Some(RingBuffer::new()) };
|
||||||
|
|
||||||
let rb = unsafe { &mut RB };
|
let rb = unsafe { RB.as_mut().unwrap() };
|
||||||
|
|
||||||
rb.enqueue(0).unwrap();
|
rb.enqueue(0).unwrap();
|
||||||
rb.enqueue(1).unwrap();
|
rb.enqueue(1).unwrap();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user