pub use crate::__shape_contract as shape_contract;
#[doc(hidden)]
#[macro_export]
macro_rules! __shape_contract {
($($t:tt)*) => {
{
extern crate alloc;
#[allow(unused_imports)]
use alloc::boxed::Box;
#[allow(unused_imports)]
use $crate::contracts::{ShapeContract, DimExpr, DimMatcher};
$crate::__proc_shape_contract!($($t)*)
}};
}
pub use crate::__run_periodically as run_periodically;
#[doc(hidden)]
#[macro_export]
macro_rules! __run_periodically {
($code:expr) => {
$crate::__run_periodically!(@internal 1000, $code)
};
($lock:block) => {
$crate::__run_periodically!(@internal 1000, $block)
};
($period:literal, $code:expr) => {
$crate::__run_periodically!(@internal $period, $code)
};
($period:literal, $lock:block) => {
$crate::__run_periodically!(@internal $period, $block)
};
(@internal $period:literal, $($tt:tt)*) => {{
if {
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
static PERIOD: AtomicUsize = AtomicUsize::new(1);
static COUNTER: AtomicUsize = AtomicUsize::new(0);
let effective_period = PERIOD.load(Ordering::Relaxed);
let count = COUNTER.fetch_add(1, Ordering::Relaxed);
if effective_period == 1 && count < 10 {
true
} else if (count % effective_period) == 0 {
if effective_period < $period {
PERIOD.store(
(2 * effective_period).clamp(1, $period),
Ordering::Relaxed,
);
}
if effective_period < $period || count > $period * 100 {
COUNTER.store(1, Ordering::Relaxed);
}
true
} else {
false
}
} {
$($tt)*
}
}};
}
pub use crate::__define_shape_contract as define_shape_contract;
#[macro_export]
#[doc(hidden)]
macro_rules! __define_shape_contract {
($name:ident, [ $($contract_expr:tt)* ] $(,)?) => {
static $name: $crate::contracts::ShapeContract<'static> = $crate::contracts::shape_contract![$($contract_expr)*];
};
}
pub use crate::__assert_shape_contract as assert_shape_contract;
#[doc(hidden)]
#[macro_export]
macro_rules! __assert_shape_contract {
([ $($contract_expr:tt)* ], $($args:tt)*) => {{
$crate::__define_shape_contract!(CONTRACT, [ $($contract_expr)* ]);
$crate::__assert_shape_contract!(CONTRACT, $($args)*)
}};
($name:ident, $shape:expr, $bindings:expr $(,)?) => {
$name.assert_shape($shape, $bindings)
};
}
pub use crate::__assert_shape_contract_periodically as assert_shape_contract_periodically;
#[doc(hidden)]
#[macro_export]
macro_rules! __assert_shape_contract_periodically {
($($args:tt)*) => {
$crate::__run_periodically!($crate::__assert_shape_contract!($($args)*))
};
}
pub use crate::__unpack_shape_contract as unpack_shape_contract;
#[doc(hidden)]
#[macro_export]
macro_rules! __unpack_shape_contract {
([ $($keys:literal),* $(,)? ], $shape:expr $(,)?) => {{
$crate::__define_shape_contract!(CONTRACT, [ $($keys),* ]);
$crate::__unpack_shape_contract!(CONTRACT, $shape, &[ $($keys),* ], &[])
}};
([ $($contract_expr:tt)* ], $($args:tt)*) => {{
$crate::__define_shape_contract!(CONTRACT, [ $($contract_expr)* ]);
$crate::__unpack_shape_contract!(CONTRACT, $($args)*)
}};
($contract:ident, $shape:expr, $keys:expr, $bindings:expr $(,)?) => {{
$contract.unpack_shape($shape, $keys, $bindings)
}};
($contract:ident, $shape:expr, $keys:expr $(,)?) => {{
$crate::__unpack_shape_contract!($contract, $shape, $keys, &[])
}};
}
#[cfg(test)]
mod tests {
use alloc::{
vec,
vec::Vec,
};
use super::*;
#[test]
fn test_run_periodically() {
let expected = vec![
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264, 520, 1032, 2032,
];
{
let mut results = Vec::new();
for i in 0..2500 {
run_periodically!({
results.push(i);
});
}
assert_eq!(&results, &expected);
}
{
let mut results = Vec::new();
for i in 0..2500 {
run_periodically!(results.push(i));
}
assert_eq!(&results, &expected);
}
}
}