vidya/crates/renderer_resources/src/util.rs

171 lines
4.4 KiB
Rust

pub(crate) mod weak_vec {
#![allow(dead_code)]
//! Module containing the [`WeakVec`] API.
use std::{sync::Weak, vec::Vec};
/// An optimized container for `Weak` references of `T` that minimizes reallocations by
/// dropping older elements that no longer have strong references to them.
#[derive(Debug)]
pub(crate) struct WeakVec<T> {
inner: Vec<Weak<T>>,
}
impl<T> Default for WeakVec<T> {
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
impl<T> WeakVec<T> {
pub(crate) fn new() -> Self {
Self { inner: Vec::new() }
}
/// Pushes a new element to this collection.
///
/// If the inner Vec needs to be reallocated, we will first drop older elements that
/// no longer have strong references to them.
pub(crate) fn push(&mut self, value: Weak<T>) {
if self.inner.len() == self.inner.capacity() {
// Iterating backwards has the advantage that we don't do more work than we have to.
for i in (0..self.inner.len()).rev() {
if self.inner[i].strong_count() == 0 {
self.inner.swap_remove(i);
}
}
// Make sure our capacity is twice the number of live elements.
// Leaving some spare capacity ensures that we won't re-scan immediately.
self.inner.reserve_exact(self.inner.len());
}
self.inner.push(value);
}
}
pub(crate) struct WeakVecIter<T> {
inner: std::vec::IntoIter<Weak<T>>,
}
impl<T> Iterator for WeakVecIter<T> {
type Item = Weak<T>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl<T> IntoIterator for WeakVec<T> {
type Item = Weak<T>;
type IntoIter = WeakVecIter<T>;
fn into_iter(self) -> Self::IntoIter {
WeakVecIter {
inner: self.inner.into_iter(),
}
}
}
}
pub(crate) use weak_vec::WeakVec;
pub fn eq_f32(lhs: f32, rhs: f32) -> bool {
use core::num::FpCategory::*;
match (lhs.classify(), rhs.classify()) {
(Zero, Zero) | (Nan, Nan) => true,
(Infinite, Infinite) => lhs.signum() == rhs.signum(),
_ => lhs == rhs,
}
}
pub fn ord_f32(lhs: f32, rhs: f32) -> core::cmp::Ordering {
use core::cmp::Ordering;
use core::num::FpCategory::*;
match (lhs.classify(), rhs.classify()) {
(Zero, Zero) | (Nan, Nan) => Ordering::Equal,
(Infinite, Infinite) => {
core::cmp::PartialOrd::partial_cmp(&lhs.signum(), &rhs.signum()).unwrap()
}
_ => core::cmp::PartialOrd::partial_cmp(&lhs, &rhs).unwrap(),
}
}
pub fn hash_f32<H: std::hash::Hasher>(state: &mut H, f: f32) {
use std::hash::Hash;
let classify = f.classify();
match classify {
std::num::FpCategory::Nan => (classify as u8).hash(state),
std::num::FpCategory::Infinite | std::num::FpCategory::Zero => {
(classify as u8, f.signum() as i8).hash(state)
}
std::num::FpCategory::Subnormal | std::num::FpCategory::Normal => f.to_bits().hash(state),
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct F32(f32);
impl F32 {
#[inline]
pub fn from_bits(bits: u32) -> Self {
Self(f32::from_bits(bits))
}
#[inline]
pub fn into_bits(self) -> u32 {
self.0.to_bits()
}
}
impl From<f32> for F32 {
fn from(value: f32) -> Self {
Self(value)
}
}
impl From<F32> for f32 {
fn from(value: F32) -> Self {
value.0
}
}
impl std::ops::Deref for F32 {
type Target = f32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for F32 {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl PartialEq for F32 {
fn eq(&self, other: &Self) -> bool {
eq_f32(self.0, other.0)
}
}
impl Eq for F32 {}
impl PartialOrd for F32 {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(ord_f32(self.0, other.0))
}
}
impl Ord for F32 {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
ord_f32(self.0, other.0)
}
}
impl core::hash::Hash for F32 {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
hash_f32(state, self.0)
}
}