commit
c26b45e452
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
*~
|
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "flan-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Avril <flanchan@cumallover.me>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["macros"]
|
||||||
|
|
||||||
|
# #![no_std] support
|
||||||
|
no_std = []
|
||||||
|
|
||||||
|
# Enable the macros section
|
||||||
|
macros = []
|
||||||
|
|
||||||
|
[dependencies]
|
@ -0,0 +1,5 @@
|
|||||||
|
//! Collection of helpers / utilities
|
||||||
|
|
||||||
|
#![cfg_attr(feature="no_std", no_std)]
|
||||||
|
|
||||||
|
#[cfg(feature="macros")] #[macro_use] pub mod macros;
|
@ -0,0 +1,166 @@
|
|||||||
|
//! Various utility macros
|
||||||
|
|
||||||
|
/// Create a duration with time suffix `h`, `m`, `s`, `ms` or `ns`.
|
||||||
|
///
|
||||||
|
/// # Combination
|
||||||
|
/// These can also be combined.
|
||||||
|
/// ```
|
||||||
|
/// # use flan_utils::duration;
|
||||||
|
/// duration!(1 h, 20 m, 30 s);
|
||||||
|
/// ```
|
||||||
|
#[macro_export] macro_rules! duration
|
||||||
|
{
|
||||||
|
(0 $($_any:tt)?) => (::core::time::Duration::from_secs(0));
|
||||||
|
($dur:literal ms) => (::core::time::Duration::from_millis($dur));
|
||||||
|
($dur:literal ns) => (::core::time::Duration::from_nanos($dur));
|
||||||
|
($dur:literal s) => (::core::time::Duration::from_secs($dur));
|
||||||
|
($dur:literal m) => (::core::time::Duration::from_secs($dur * 60));
|
||||||
|
($dur:literal h) => (::core::time::Duration::from_secs($dur * 60 * 60));
|
||||||
|
|
||||||
|
( $($dur:literal $unit:tt),*)=> {
|
||||||
|
duration!(0 s) $(
|
||||||
|
+ duration!($dur $unit)
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `String` object from a literal.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use flan_utils::string;
|
||||||
|
/// let string = string!("Hello");
|
||||||
|
/// assert_eq!("Hello", string.as_str());
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(feature="no_std"))]
|
||||||
|
#[macro_export] macro_rules! string {
|
||||||
|
($string:literal) => (::std::string::String::from($string));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// A 'soft' assertion of the type `Result<(), impl Error + 'static>`.
|
||||||
|
///
|
||||||
|
/// # Return type
|
||||||
|
/// The error type created when the condition fails is an opaque ZST which implements `Debug, Clone, Copy, Display, Error`.
|
||||||
|
/// When formatted, it prints the assertion message provided (or "Assertion failed" if none was), as well as a `stringify!` of the failed condition.
|
||||||
|
///
|
||||||
|
/// It also has two methods:
|
||||||
|
/// ```ignore
|
||||||
|
/// /// The expression that failed as a string.
|
||||||
|
/// #[inline] pub const fn expression(&self) -> &'static str;
|
||||||
|
/// ```
|
||||||
|
/// ```ignore
|
||||||
|
/// /// The assertion message.
|
||||||
|
/// ///
|
||||||
|
/// /// If one was not provided, this will be "Assertion failed".
|
||||||
|
/// #[inline] pub const fn message(&self) -> &'static str;
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(feature="no_std"))]
|
||||||
|
#[macro_export] macro_rules! soft_assert {
|
||||||
|
//TODO: Rework, change this back to $(; $message:literal)?, have "Assertion failed" always prepended to the write, and the message conditionally added to the `concat!()` and `self.message()` return the empty string when one was not present.
|
||||||
|
($cond:expr; $message:literal) => {
|
||||||
|
if !$cond {
|
||||||
|
use ::std::{fmt, error};
|
||||||
|
|
||||||
|
/// Opaque type created within macro `soft_assert`.
|
||||||
|
///
|
||||||
|
/// This type implements `std::{fmt::{Display, Debug}, error::Error}` and is a ZST which implements `Copy`.
|
||||||
|
///
|
||||||
|
/// It also has two methods:
|
||||||
|
/// ```ignore
|
||||||
|
/// /// The expression that failed as a string.
|
||||||
|
/// #[inline] pub const fn expression(&self) -> &'static str;
|
||||||
|
/// ```
|
||||||
|
/// ```ignore
|
||||||
|
/// /// The assertion message.
|
||||||
|
/// ///
|
||||||
|
/// /// If one was not provided, this will be "Assertion failed".
|
||||||
|
/// #[inline] pub const fn message(&self) -> &'static str;
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct SoftAssertionFailedError;
|
||||||
|
|
||||||
|
impl error::Error for SoftAssertionFailedError{}
|
||||||
|
impl fmt::Display for SoftAssertionFailedError
|
||||||
|
{
|
||||||
|
#[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, concat!($message, ": ", stringify!($cond)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoftAssertionFailedError
|
||||||
|
{
|
||||||
|
/// The expression that failed as a string.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline] pub const fn expression(&self) -> &'static str
|
||||||
|
{
|
||||||
|
stringify!($cond)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// The assertion message.
|
||||||
|
///
|
||||||
|
/// If one was not provided, this will be "Assertion failed".
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline] pub const fn message(&self) -> &'static str
|
||||||
|
{
|
||||||
|
$message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(SoftAssertionFailedError)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($cond:expr) => {
|
||||||
|
$crate::soft_assert!($cond; "Assertion failed")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests
|
||||||
|
{
|
||||||
|
use crate::*;
|
||||||
|
#[test]
|
||||||
|
fn duration()
|
||||||
|
{
|
||||||
|
use core::time::Duration;
|
||||||
|
assert_eq!(duration!(100 ms), Duration::from_millis(100));
|
||||||
|
assert_eq!(duration!(1 h, 20 m, 30 s), duration!(1 h) + duration!(20 m) + duration!(30 s));
|
||||||
|
assert_eq!(duration!(3 s, 20 ms, 100 ns), Duration::from_nanos(100) + Duration::from_millis(20) + Duration::from_secs(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature="no_std"))]
|
||||||
|
fn sort_assert()
|
||||||
|
{
|
||||||
|
let arr = [100; 12];
|
||||||
|
|
||||||
|
let ass = soft_assert!(arr.len() == 12);
|
||||||
|
println!("Ass (expect true): {:?}", ass);
|
||||||
|
ass.expect("ass 1 expected true");
|
||||||
|
|
||||||
|
let ass = soft_assert!(arr[0] - 50 != 50);
|
||||||
|
println!("Ass (expect false): {:?}", ass);
|
||||||
|
ass.expect_err("ass 1 expected false");
|
||||||
|
|
||||||
|
if let Err(err) = soft_assert!(arr[0] - 50 > arr[1]; "Assertion failed: Element was too small")
|
||||||
|
{
|
||||||
|
println!("Ass err `message()`: {}", err.message());
|
||||||
|
println!("Ass err `expression()`: {}", err.expression());
|
||||||
|
println!("\n-> {}", err);
|
||||||
|
} else {
|
||||||
|
panic!("ass 3 expected false");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature="no_std"))]
|
||||||
|
fn string()
|
||||||
|
{
|
||||||
|
let string: String = string!("Hello world");
|
||||||
|
assert_eq!(&string[..], "Hello world");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue