#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[must_use = "It is expected that the return value of a `FoundValue` is used for something"]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub enum FoundValue<V> {
#[default]
NotFound,
Found(V),
}
impl<V> core::ops::Try for FoundValue<V> {
type Output = ();
type Residual = V;
fn from_output((): ()) -> Self {
Self::NotFound
}
fn branch(self) -> core::ops::ControlFlow<V, ()> {
match self {
Self::NotFound => core::ops::ControlFlow::Continue(()),
Self::Found(v) => core::ops::ControlFlow::Break(v),
}
}
}
impl<V> Unwrap<V> for FoundValue<V> {
fn unwrap(self) -> V {
match self {
Self::Found(val) => val,
Self::NotFound => {
panic!("called `Unwrap::unwrap()` on a `NotFound` value")
}
}
}
fn unwrap_or(self, default: V) -> V {
match self {
Self::Found(val) => val,
Self::NotFound => default,
}
}
unsafe fn unwrap_unchecked(self) -> V {
match self {
Self::Found(val) => val,
Self::NotFound => core::hint::unreachable_unchecked(),
}
}
}
impl<V: Default> UnwrapDefault<V> for FoundValue<V> {
fn unwrap_or_default(self) -> V {
match self {
Self::Found(val) => val,
Self::NotFound => V::default(),
}
}
}
pub trait ToFoundValue<T> {
fn found_error(self) -> FoundValue<T>;
}
impl<T, E> ToFoundValue<E> for Result<T, E> {
fn found_error(self) -> FoundValue<E> {
match self {
Self::Ok(_) => FoundValue::NotFound,
Self::Err(val) => FoundValue::Found(val),
}
}
}
impl<E> ToFoundValue<E> for Option<E> {
fn found_error(self) -> FoundValue<E> {
match self {
Self::None => FoundValue::NotFound,
Self::Some(val) => FoundValue::Found(val),
}
}
}
impl<V> core::ops::FromResidual<V> for FoundValue<V> {
fn from_residual(residual: V) -> Self {
Self::Found(residual)
}
}
impl<E> core::ops::FromResidual<Result<core::convert::Infallible, E>> for FoundValue<E> {
fn from_residual(residual: Result<core::convert::Infallible, E>) -> Self {
match residual {
Err(e) => Self::Found(e),
}
}
}
impl<T> From<Option<T>> for FoundValue<T> {
fn from(val: Option<T>) -> Self {
val.map_or_else(|| Self::NotFound, |val| Self::Found(val))
}
}
impl<T> FromPatch<Option<T>> for FoundValue<T> {
fn from_value(val: Option<T>) -> Self {
val.map_or_else(|| Self::NotFound, |val| Self::Found(val))
}
}
impl<T> From<T> for FoundValue<T> {
fn from(val: T) -> Self {
Self::Found(val)
}
}
impl<T> FromPatch<T> for FoundValue<T> {
fn from_value(val: T) -> Self {
Self::Found(val)
}
}
#[cfg(feature = "std")]
pub mod copyable_list;
#[cfg(feature = "std")]
mod codec;
#[cfg(feature = "std")]
pub use codec::*;
#[cfg(feature = "std")]
pub mod skipping_text_type;
#[cfg(feature = "keycodes")]
#[cfg(feature = "std")]
pub mod keybinds;
#[cfg(feature = "std")]
use core::hash::Hasher;
#[cfg(feature = "std")]
pub fn concatenate<A: AsRef<str>, B: AsRef<str>>(a: A, b: B) -> String {
let mut result = String::from(a.as_ref());
result.push_str(b.as_ref());
result
}
#[cfg(feature = "std")]
pub fn hash_value<T: core::hash::Hash>(value: &T) -> u64 {
let mut s = std::hash::DefaultHasher::new();
value.hash(&mut s);
s.finish()
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(
feature = "wincode",
derive(wincode::SchemaWrite, wincode::SchemaRead)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct RatioConverter2D<T: IntoPatch<F>, F: IntoPatch<T> + Copy> {
ratio: (F, F),
inverse_ratio: (F, F),
phantom: core::marker::PhantomData<T>,
}
use crate::prelude::{FromPatch, IntoPatch, Unwrap, UnwrapDefault};
#[allow(clippy::missing_const_for_fn)]
const impl<
T: [const] core::ops::Add<Output = T>
+ [const] core::ops::Sub<Output = T>
+ [const] core::ops::Mul<Output = T>
+ [const] core::ops::Div<Output = T>
+ Copy
+ [const] IntoPatch<F>,
F: [const] IntoPatch<T>
+ [const] core::ops::Add<Output = F>
+ [const] core::ops::Sub<Output = F>
+ [const] core::ops::Mul<Output = F>
+ [const] core::ops::Div<Output = F>
+ Copy,
> RatioConverter2D<T, F>
{
#[must_use]
pub fn new(smaller: (T, T), bigger: (T, T)) -> Self {
Self {
ratio: (
(smaller.0).into_value() / (bigger.0).into_value(),
(smaller.1).into_value() / (bigger.1).into_value(),
),
inverse_ratio: (
(bigger.0).into_value() / (smaller.0).into_value(),
(bigger.1).into_value() / (smaller.1).into_value(),
),
phantom: core::marker::PhantomData,
}
}
pub fn smaller_to_bigger(&self, value: (T, T)) -> (T, T) {
(
((value.0).into_value() * self.inverse_ratio.0).into_value(),
((value.1).into_value() * self.inverse_ratio.1).into_value(),
)
}
pub fn bigger_to_smaller(&self, value: (T, T)) -> (T, T) {
(
((value.0).into_value() * self.ratio.0).into_value(),
((value.1).into_value() * self.ratio.1).into_value(),
)
}
}
#[cfg(target_os = "windows")]
#[cfg(feature = "system")]
#[cfg(feature = "std")]
pub mod windows {
use windows::Win32::System::Memory::{
VirtualQuery, MEMORY_BASIC_INFORMATION,
};
#[allow(trivial_casts)]
#[allow(clippy::ref_as_ptr)]
pub fn get_actual_stack_info() {
unsafe {
let current_sp = (&0 as *const i32).cast::<std::ffi::c_void>(); let mut mbi = MEMORY_BASIC_INFORMATION::default();
VirtualQuery(
Some(current_sp),
&raw mut mbi,
std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
);
let region_base = mbi.BaseAddress as usize;
let region_size = mbi.RegionSize;
let current_addr = current_sp as usize;
println!("Memory region base: 0x{region_base:x}");
println!("Memory region size: {} MB", region_size / 1024 / 1024);
println!("Current SP: 0x{current_addr:x}");
println!(
"Offset in region: {} KB",
(current_addr - region_base) / 1024
);
let used_from_top = (region_base + region_size) - current_addr;
println!("Used from region top: {} KB", used_from_top / 1024);
}
}
}
#[macro_export]
macro_rules! compile_warn {
($msg:expr) => {
#[allow(dead_code)]
fn deprecated_container() {
#[deprecated(note = $msg)]
const fn deprecated_trigger() {}
let _ = deprecated_trigger;
}
};
}
#[must_use]
#[cfg(feature = "std")]
pub fn type_name_of_val<T>(_: &T) -> &'static str {
std::any::type_name::<T>()
}
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub enum TwoOptions<O1, O2> {
Option1(O1),
Option2(O2),
}
pub const trait EasyUnwrapUnchecked<T> {
fn easy_unwrap_unchecked(self) -> T;
}
impl<T> EasyUnwrapUnchecked<T> for Option<T> {
fn easy_unwrap_unchecked(self) -> T {
unsafe { self.unwrap_unchecked() }
}
}
impl<T, E> EasyUnwrapUnchecked<T> for Result<T, E> {
fn easy_unwrap_unchecked(self) -> T {
unsafe { self.unwrap_unchecked() }
}
}
#[cfg(feature = "std")]
mod map_extension;
#[cfg(feature = "std")]
pub use map_extension::*;
mod scrollable_container;
pub use scrollable_container::*;
#[cfg(feature = "std")]
mod clone_any;
#[cfg(feature = "std")]
pub use clone_any::*;
#[macro_export]
macro_rules! impl_empty_trait {
($name:ident for $($t:ty),* $(,)?) => {
$(
impl $name for $t {}
)*
};
}
#[cfg(feature = "std")]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct Ticker {
pub target_delta_time: std::time::Duration,
pub last_frame: std::time::Instant,
pub next_frame: std::time::Instant,
pub delta_time: std::time::Duration,
}
#[cfg(feature = "std")]
impl Ticker {
#[must_use]
pub fn new(fps: f64) -> Option<Self> {
Some(Self {
target_delta_time: std::time::Duration::try_from_secs_f64(
1.0 / fps,
)
.ok()?,
last_frame: std::time::Instant::now(),
next_frame: std::time::Instant::now(),
delta_time: std::time::Duration::new(0, 0),
})
}
pub fn tick(&mut self) {
let now = std::time::Instant::now();
self.delta_time = now - self.last_frame;
self.last_frame = now;
if now > self.next_frame {
self.next_frame = now + self.target_delta_time;
} else {
std::thread::sleep(self.next_frame - now);
self.next_frame += self.target_delta_time;
}
}
#[must_use]
pub const fn get_delta_time(&self) -> std::time::Duration {
self.delta_time
}
#[must_use]
pub const fn get_delta_time_and_fps_f32(&self) -> (f32, f32) {
let delta = self.delta_time.as_secs_f32();
(delta, 1.0 / delta)
}
#[must_use]
pub const fn get_delta_time_and_fps_f64(&self) -> (f64, f64) {
let delta = self.delta_time.as_secs_f64();
(delta, 1.0 / delta)
}
}
#[cfg(feature = "std")]
pub mod scene;
#[cfg(feature = "std")]
#[must_use]
pub fn bytes_to_mixed_string(bytes: &[u8]) -> String {
let mut out = String::new();
let mut i = 0;
while i < bytes.len() {
match std::str::from_utf8(&bytes[i..]) {
Ok(s) => {
out.push_str(s);
break;
}
Err(e) => {
let valid = e.valid_up_to();
if valid > 0 {
out.push_str(
std::str::from_utf8(&bytes[i..i + valid])
.easy_unwrap_unchecked(),
);
i += valid;
} else {
out.push_str(&format!("\\x{:02X}", bytes[i]));
i += 1;
}
}
}
}
out
}
#[cfg(feature = "std")]
#[must_use]
pub fn bit_str_to_bits(bit_str: &str) -> Option<Vec<bool>> {
bit_str
.chars()
.map(|x| match x {
'0' => Some(false),
'1' => Some(true),
_ => None,
})
.collect()
}
#[cfg(feature = "std")]
pub mod buffer_extension {
use crate::Buffer;
pub fn buffer_from_bitmask(
mask: &[bool],
size: (usize, usize),
color_0: u32,
color_1: u32,
) -> Result<Buffer, String> {
let mut new = Vec::with_capacity(mask.len());
for i in mask {
if *i {
new.push(color_1);
} else {
new.push(color_0);
}
}
Buffer::new(size, new)
}
}