#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
pub type BoxedFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + 'a>>;
pub type SendSyncBoxedFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send + Sync + 'a>>;
pub type SendBoxedFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;
pub mod sync;
pub mod r#async;
pub mod bit_array;
pub mod copy_fn;
pub mod stable_vec;
pub mod stale_map;
use std::ops::Div;
pub type Box<T> = smallbox::SmallBox<T, [u8; 32]>;
pub use copy_fn::{InlineCopyFn, InlineCopyFnError, RefCall1, RefCall2, RefCall3};
pub use gxhash as hash;
pub use sonic_rs as json;
pub use stable_vec::{StableVec, StableVecHandle};
pub struct BufferAllocator<'a> {
buffer: &'a mut [u8],
offset: usize,
}
impl<'a> BufferAllocator<'a> {
pub fn new(buffer: &'a mut [u8]) -> Self {
Self { buffer, offset: 0 }
}
pub fn take(&mut self, size: usize) -> &'a mut [u8] {
self.take_with_offset(size).1
}
pub fn take_with_offset(&mut self, size: usize) -> (usize, &'a mut [u8]) {
let offset = self.offset;
let buffer = &mut self.buffer[self.offset..][..size];
self.offset += size;
(offset, unsafe { std::mem::transmute::<&mut [u8], &'a mut [u8]>(buffer) })
}
pub fn take_with_offset_aligned(&mut self, size: usize, alignment: usize) -> (usize, &'a mut [u8]) {
self.offset = self.offset.next_multiple_of(alignment.max(1));
self.take_with_offset(size)
}
pub fn remaining_aligned(&self, alignment: usize) -> usize {
self.buffer
.len()
.saturating_sub(self.offset.next_multiple_of(alignment.max(1)))
}
pub fn remaining(&self) -> usize {
self.buffer.len().saturating_sub(self.offset)
}
}
pub fn partition<T>(slice: &[T], key_fn: impl Fn(&T) -> usize) -> Vec<(usize, &[T])> {
let mut partitions = Vec::new();
let mut slice_start = 0;
for i in 1..slice.len() {
if key_fn(&slice[i - 1]) + 1usize != key_fn(&slice[i]) {
partitions.push((key_fn(&slice[slice_start]), &slice[slice_start..i]));
slice_start = i;
}
}
if !slice.is_empty() {
partitions.push((key_fn(&slice[slice_start]), &slice[slice_start..]));
}
partitions
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Extent {
width: u32,
height: u32,
depth: u32,
}
impl Extent {
pub fn new(width: u32, height: u32, depth: u32) -> Self {
Self { width, height, depth }
}
pub fn line(width: u32) -> Self {
Self {
width,
height: 0,
depth: 0,
}
}
pub fn square(size: u32) -> Self {
Self {
width: size,
height: size,
depth: 0,
}
}
pub fn rectangle(width: u32, height: u32) -> Self {
Self { width, height, depth: 0 }
}
pub fn cube(width: u32, height: u32, depth: u32) -> Self {
Self { width, height, depth }
}
pub fn as_tuple(&self) -> (u32, u32, u32) {
(self.width, self.height, self.depth)
}
pub fn as_array(&self) -> [u32; 3] {
[self.width, self.height, self.depth]
}
#[inline]
pub fn width(&self) -> u32 {
self.width
}
#[inline]
pub fn height(&self) -> u32 {
self.height
}
#[inline]
pub fn depth(&self) -> u32 {
self.depth
}
pub fn aspect_ratio(&self) -> f32 {
(self.width as f32) / (self.height as f32)
}
pub fn dimensions(&self) -> u32 {
if self.width == 0 {
0
} else if self.depth > 1 {
3
} else if self.height > 1 {
2
} else {
1
}
}
}
impl From<[u32; 3]> for Extent {
fn from(array: [u32; 3]) -> Self {
Self {
width: array[0],
height: array[1],
depth: array[2],
}
}
}
impl Div<u32> for Extent {
type Output = Self;
fn div(self, rhs: u32) -> Self::Output {
Self {
width: if self.width == 1 { 1 } else { self.width / rhs },
height: if self.height == 1 { 1 } else { self.height / rhs },
depth: if self.depth == 1 { 1 } else { self.depth / rhs },
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct RGBA {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
impl std::ops::Mul for RGBA {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self {
r: self.r * rhs.r,
g: self.g * rhs.g,
b: self.b * rhs.b,
a: self.a * rhs.a,
}
}
}
impl std::ops::Mul<f32> for RGBA {
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Self {
r: self.r * rhs,
g: self.g * rhs,
b: self.b * rhs,
a: self.a * rhs,
}
}
}
impl std::hash::Hash for RGBA {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.r.to_bits().hash(state);
self.g.to_bits().hash(state);
self.b.to_bits().hash(state);
self.a.to_bits().hash(state);
}
}
impl RGBA {
pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
Self { r, g, b, a }
}
pub fn black() -> Self {
Self {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
}
}
pub fn white() -> Self {
Self {
r: 1.0,
g: 1.0,
b: 1.0,
a: 1.0,
}
}
pub fn transparent() -> Self {
Self {
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.0,
}
}
}
impl Default for RGBA {
fn default() -> Self {
Self::black()
}
}
impl From<RGBA> for [f32; 4] {
fn from(val: RGBA) -> Self {
[val.r, val.g, val.b, val.a]
}
}
pub fn insert_return_length<T>(collection: &mut Vec<T>, value: T) -> usize {
let length = collection.len();
collection.push(value);
length
}
pub fn as_byte_slice<T>(slice: &[T]) -> &[u8] {
unsafe { std::slice::from_raw_parts(slice.as_ptr().cast::<u8>(), std::mem::size_of_val(slice)) }
}
pub fn as_byte_slice_mut<T>(slice: &mut [T]) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(slice.as_mut_ptr().cast::<u8>(), std::mem::size_of_val(slice)) }
}
#[cfg(test)]
mod tests {
use std::hash::{DefaultHasher, Hash as _, Hasher as _};
use super::{as_byte_slice, as_byte_slice_mut, BufferAllocator, Extent, RGBA};
#[test]
fn test_partition() {
let input = [];
let expected: Vec<(usize, &[usize])> = vec![];
assert_eq!(super::partition(&input, |x| *x,), expected);
let input = [0];
let expected: Vec<(usize, &[usize])> = vec![(0, &[0])];
assert_eq!(super::partition(&input, |x| *x,), expected);
let input = [0, 1];
let expected: Vec<(usize, &[usize])> = vec![(0, &[0, 1])];
assert_eq!(super::partition(&input, |x| *x,), expected);
let input = [0, 2];
let expected: Vec<(usize, &[usize])> = vec![(0, &[0]), (2, &[2])];
assert_eq!(super::partition(&input, |x| *x,), expected);
let input = [1, 2, 3, 5, 6, 7, 9, 10, 11];
let expected: Vec<(usize, &[usize])> = vec![(1, &[1, 2, 3]), (5, &[5, 6, 7]), (9, &[9, 10, 11])];
assert_eq!(super::partition(&input, |x| *x,), expected);
}
#[test]
fn buffer_allocator_returns_disjoint_ranges_and_tracks_padding() {
let mut storage = [0u8; 16];
{
let mut allocator = BufferAllocator::new(&mut storage);
let (first_offset, first) = allocator.take_with_offset(3);
first.copy_from_slice(&[1, 2, 3]);
let (second_offset, second) = allocator.take_with_offset_aligned(4, 4);
second.copy_from_slice(&[4, 5, 6, 7]);
assert_eq!(first_offset, 0);
assert_eq!(second_offset, 4);
assert_eq!(allocator.remaining(), 8);
assert_eq!(allocator.remaining_aligned(8), 8);
}
assert_eq!(&storage[..8], &[1, 2, 3, 0, 4, 5, 6, 7]);
}
#[test]
fn extent_dimensions_and_division_preserve_active_axes() {
assert_eq!(Extent::line(8).dimensions(), 1);
assert_eq!(Extent::square(8).dimensions(), 2);
assert_eq!(Extent::cube(8, 4, 2).dimensions(), 3);
assert_eq!(Extent::new(8, 1, 1).dimensions(), 1);
assert_eq!(Extent::new(8, 8, 1).dimensions(), 2);
assert_eq!(Extent::new(0, 0, 0).dimensions(), 0);
assert_eq!((Extent::new(8, 1, 1) / 2).as_tuple(), (4, 1, 1));
assert_eq!((Extent::new(8, 4, 2) / 2).as_array(), [4, 2, 1]);
assert_eq!(Extent::rectangle(16, 9).aspect_ratio(), 16.0 / 9.0);
}
#[test]
fn rgba_multiplication_is_component_wise_and_hashes_all_channels() {
let tint = RGBA::new(0.5, 0.25, 1.0, 0.5);
assert_eq!(tint * RGBA::white(), tint);
assert_eq!(tint * 2.0, RGBA::new(1.0, 0.5, 2.0, 1.0));
assert_eq!(<[f32; 4]>::from(RGBA::transparent()), [0.0, 0.0, 0.0, 0.0]);
assert_eq!(RGBA::default(), RGBA::black());
let hash = |color: RGBA| {
let mut hasher = DefaultHasher::new();
color.hash(&mut hasher);
hasher.finish()
};
assert_ne!(hash(tint), hash(RGBA::new(0.5, 0.25, 1.0, 0.25)));
}
#[test]
fn byte_slice_views_preserve_native_object_representation() {
let values = [0x1122u16, 0x3344u16];
let bytes = as_byte_slice(&values);
assert_eq!(bytes.len(), std::mem::size_of_val(&values));
let mut mutable = [0u16; 2];
as_byte_slice_mut(&mut mutable).copy_from_slice(bytes);
assert_eq!(mutable, values);
}
}