initial commit

old
Avril 3 years ago
commit c26b45e452
Signed by: flanchan
GPG Key ID: 284488987C31F630

3
.gitignore vendored

@ -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…
Cancel
Save