use std::{any::type_name, collections::HashMap, hash::Hash, time::Duration};
pub mod bool_utils;
pub mod logger;
pub mod option_utils;
pub mod str_utils;
pub mod prelude {
pub use crate::bool_utils::*;
pub use crate::logger::Loggable;
pub use crate::option_utils::*;
pub use crate::str_utils::*;
pub use crate::*;
}
pub trait EqUtils<T: PartialEq> {
fn eq_to(&self, other: &T) -> bool;
fn not_eq_to(&self, other: &T) -> bool;
}
impl<T: PartialEq> EqUtils<T> for T {
fn eq_to(&self, other: &T) -> bool {
self == other
}
fn not_eq_to(&self, other: &T) -> bool {
self != other
}
}
pub trait MemUtils {
fn type_name(&self) -> &'static str;
fn mem_size(&self) -> usize;
fn view(&self);
}
impl<T> MemUtils for T {
fn type_name(&self) -> &'static str {
type_name::<T>()
}
fn mem_size(&self) -> usize {
std::mem::size_of::<T>()
}
fn view(&self) {
println!(
"[view] Type: {}, Size: {} bytes",
self.type_name(),
self.mem_size()
);
}
}
pub trait ConvertUtils: Sized {
fn to<T: TryFrom<Self>>(self) -> Option<T>;
fn to_or<T: TryFrom<Self>>(self, fallback: T) -> T;
fn to_result<T: TryFrom<Self>>(self) -> Result<T, T::Error>;
}
impl<T> ConvertUtils for T {
fn to<U: TryFrom<T>>(self) -> Option<U> {
U::try_from(self).ok()
}
fn to_or<U: TryFrom<T>>(self, fallback: U) -> U {
self.to().unwrap_or(fallback)
}
fn to_result<U: TryFrom<T>>(self) -> Result<U, U::Error> {
U::try_from(self)
}
}
pub trait VecUtils<T> {
fn push_if(&mut self, push: T, cond: bool);
fn push_if_with<F: FnOnce() -> T>(&mut self, cond: bool, f: F);
}
impl<T> VecUtils<T> for Vec<T> {
fn push_if(&mut self, push: T, cond: bool) {
if cond {
self.push(push);
}
}
fn push_if_with<F: FnOnce() -> T>(&mut self, cond: bool, f: F) {
if cond {
self.push(f());
}
}
}
pub trait MapUtils<K, V> {
fn get_or<'a>(&'a self, key: &K, fallback: &'a V) -> &'a V;
fn insert_if(&mut self, key: K, value: V, cond: bool);
}
impl<K: Eq + Hash, V> MapUtils<K, V> for HashMap<K, V> {
fn get_or<'a>(&'a self, key: &K, fallback: &'a V) -> &'a V {
self.get(key).unwrap_or(fallback)
}
fn insert_if(&mut self, key: K, value: V, cond: bool) {
if cond {
self.insert(key, value);
}
}
}
pub trait ResultUtils<T, E> {
fn if_ok<F: FnOnce(&T)>(self, f: F) -> Self;
fn if_err<F: FnOnce(&E)>(self, f: F) -> Self;
}
impl<T, E: std::fmt::Debug> ResultUtils<T, E> for Result<T, E> {
fn if_ok<F: FnOnce(&T)>(self, f: F) -> Self {
if let Ok(ref val) = self {
f(val);
}
self
}
fn if_err<F: FnOnce(&E)>(self, f: F) -> Self {
if let Err(ref err) = self {
f(err);
}
self
}
}
pub trait DurationUtils {
fn pretty(&self) -> String;
}
impl DurationUtils for Duration {
fn pretty(&self) -> String {
let total_secs = self.as_secs();
let hours = total_secs / 3600;
let mins = (total_secs % 3600) / 60;
let secs = total_secs % 60;
format!("{}h {}m {}s", hours, mins, secs)
}
}
pub trait IteratorUtils: Iterator + Sized {
fn find_map_or<T, F: FnMut(Self::Item) -> Option<T>>(self, f: F, fallback: T) -> T;
}
impl<I: Iterator> IteratorUtils for I {
fn find_map_or<T, F: FnMut(Self::Item) -> Option<T>>(mut self, f: F, fallback: T) -> T {
self.find_map(f).unwrap_or(fallback)
}
}
pub trait IdentityUtils: Sized {
fn tap<F: FnOnce(&Self)>(self, f: F) -> Self;
}
impl<T> IdentityUtils for T {
fn tap<F: FnOnce(&Self)>(self, f: F) -> Self {
f(&self);
self
}
}
pub trait PanicUtils<T> {
fn unwrap_or_exit(self, msg: &str) -> T;
}
impl<T> PanicUtils<T> for Option<T> {
fn unwrap_or_exit(self, msg: &str) -> T {
self.unwrap_or_else(|| {
eprintln!("[FATAL]: {}", msg);
std::process::exit(1);
})
}
}
impl<T, U> PanicUtils<T> for Result<T, U> {
fn unwrap_or_exit(self, msg: &str) -> T {
self.unwrap_or_else(|_| {
eprintln!("[FATAL]: {}", msg);
std::process::exit(1);
})
}
}
pub trait ClampUtils {
fn clamp_to(self, min: Self, max: Self) -> Self;
}
impl ClampUtils for i32 {
fn clamp_to(self, min: Self, max: Self) -> Self {
self.max(min).min(max)
}
}
pub trait NumberUtils {
#[must_use]
fn is_even(&self) -> bool;
#[must_use]
fn is_odd(&self) -> bool;
}
impl NumberUtils for i32 {
fn is_even(&self) -> bool {
self % 2 == 0
}
fn is_odd(&self) -> bool {
self % 2 != 0
}
}