This commit is contained in:
Intege-rs
2024-11-13 21:41:26 -05:00
commit 03066e2e55
29 changed files with 1549 additions and 0 deletions

80
sub/core/src/arrays.rs Normal file
View File

@@ -0,0 +1,80 @@
use core::fmt::{Debug, Formatter};
pub fn fill_with<T, F: FnMut(usize) -> T>(slice: &mut [T], mut func: F) {
slice.iter_mut().enumerate().for_each(|(i,v)|*v = func(i))
}
pub struct FixedVec<const MAX_LEN: usize, T> {
length: usize,
buffer: [core::mem::MaybeUninit<T>;MAX_LEN],
}
impl<const MAX_LEN: usize, T: Sized> FixedVec<MAX_LEN, T> {
pub fn new() -> Self {
unsafe { core::mem::zeroed() }
}
pub fn push(&mut self, value: T) -> Option<()> {
if self.length >= MAX_LEN { return None }
unsafe { *self.buffer[self.length].as_mut_ptr() = value };
self.length += 1;
Some(())
}
pub fn pop(&mut self) -> Option<T> {
if self.length == 0 { return None }
self.length -= 1;
Some(unsafe { self.buffer[self.length].assume_init_read() })
}
pub fn extend<Iter: Iterator<Item=T>>(&mut self, mut iter: Iter) -> Result<usize, usize> {
let mut count = 0;
loop {
if self.length == MAX_LEN {
return Err(count);
}
match iter.next() {
None => return Ok(count),
Some(value) => {
unsafe { *self.buffer[self.length].as_mut_ptr() = value };
self.length += 1;
count += 1;
}
}
}
}
pub fn as_slice(&self) -> &[T] {
// length can't be larger than MaxLen, use unsafe to dodge the panic
unsafe { core::slice::from_raw_parts(self.buffer.as_ptr() as *const T, self.length) }
}
pub fn clear(&mut self) {
self.length = 0;
}
}
impl<const MAX_LEN: usize, T: Debug> Debug for FixedVec<MAX_LEN, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
Debug::fmt(self.as_slice(), f)
}
}
impl<const MAX_LEN: usize, T> Drop for FixedVec<MAX_LEN, T> {
fn drop(&mut self) {
for e in &mut self.buffer[..self.length] {
unsafe { e.assume_init_drop() }
}
}
}
impl<const MAX_LEN: usize> core::fmt::Write for FixedVec<MAX_LEN, u8> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
_=self.extend(s.as_bytes().iter().cloned());
Ok(())
}
}

56
sub/core/src/branching.rs Normal file
View File

@@ -0,0 +1,56 @@
use core::sync::atomic::Ordering;
/// Runs code on drop
#[repr(transparent)]
pub struct OnDrop<F: FnOnce()>(
// Use a MaybeUninit so we have finer control over when this type is dropped
core::mem::MaybeUninit<F>
);
impl<F: FnOnce()> OnDrop<F> {
pub fn new(fun: F) -> Self {
Self(core::mem::MaybeUninit::new(fun))
}
pub fn cancel(mut self) {
// invoke the functions destructor but not our own
unsafe { self.0.assume_init_drop(); }
core::mem::forget(self);
}
}
impl<F: FnOnce()> Drop for OnDrop<F> {
fn drop(&mut self) {
unsafe { self.0.assume_init_read()() };
}
}
#[repr(transparent)]
pub struct Once(core::sync::atomic::AtomicBool);
impl Once {
pub const fn new() -> Self {
Self(core::sync::atomic::AtomicBool::new(false))
}
#[inline(always)]
pub fn first(&self) -> bool {
!self.0.swap(true, Ordering::Acquire)
}
}
pub macro once() {
{
static _ONCE: Once = Once::new();
_ONCE.first()
}
}

View File

@@ -0,0 +1,96 @@
/// Allows the safe conversion from smaller integer types into larger ones
/// Does not allow signed types to be cast into unsigned types
pub trait Upcast<T> {
fn upcast(self) -> T;
}
/// Utility trait for casting between types...
pub trait As<T> {
fn cast(self) -> T;
}
macro_rules! gen_cast {
($typ1:ty => $($typ2:ty),*) => {
$(impl As<$typ2> for $typ1 { #[inline(always)] fn cast(self) -> $typ2 { self as _ } })*
};
($G:ident > $typ1:ty => $($typ2:ty),*) => {
$(impl<$G> As<$typ2> for $typ1 { #[inline(always)] fn cast(self) -> $typ2 { self as _ } })*
}
}
macro_rules! gen_upcast {
($from:ty => $into:ty) => {
impl Upcast<$into> for $from {
fn upcast(self) -> $into {
self as $into
}
}
};
}
gen_cast!(u8 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(u16 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(u32 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(u64 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(u128 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(i8 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(i16 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(i32 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(i64 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(i128 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(usize => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(isize => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(T>*const T => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
gen_cast!(T>*mut T => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);
impl<F,T> As<*const T> for *const F { fn cast(self) -> *const T { self as _ } }
impl<F,T> As<*mut T> for *const F { fn cast(self) -> *mut T { self as _ } }
impl<F,T> As<*const T> for *mut F { fn cast(self) -> *const T { self as _ } }
impl<F,T> As<*mut T> for *mut F { fn cast(self) -> *mut T { self as _ } }
impl<T> As<*const T> for &T { fn cast(self) -> *const T { self as _ } }
impl<T> As<*mut T> for &mut T { fn cast(self) -> *mut T { self as _ } }
// Unsigned
gen_upcast!(u8 => u8);
gen_upcast!(u8 => u16);
gen_upcast!(u8 => u32);
gen_upcast!(u8 => u64);
gen_upcast!(u16 => u16);
gen_upcast!(u16 => u32);
gen_upcast!(u16 => u64);
gen_upcast!(u32 => u32);
gen_upcast!(u32 => u64);
gen_upcast!(u64 => u64);
// Signed
gen_upcast!(i8 => i8);
gen_upcast!(i8 => i16);
gen_upcast!(i8 => i32);
gen_upcast!(i8 => i64);
gen_upcast!(i16 => i16);
gen_upcast!(i16 => i32);
gen_upcast!(i16 => i64);
gen_upcast!(i32 => i32);
gen_upcast!(i32 => i64);
gen_upcast!(i64 => i64);
// Pointer Sized
gen_upcast!(u8 => usize);
gen_upcast!(i8 => isize);
gen_upcast!(u16 => usize);
gen_upcast!(i16 => isize);
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
gen_upcast!(u32 => usize);
#[cfg(any(target_pointer_width = "64"))]
gen_upcast!(u64 => usize);
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
gen_upcast!(i32 => isize);
#[cfg(any(target_pointer_width = "64"))]
gen_upcast!(i64 => isize);
gen_upcast!(isize => isize);
gen_upcast!(usize => usize);

49
sub/core/src/data.rs Normal file
View File

@@ -0,0 +1,49 @@
use core::cmp::Ordering;
use crate::cast_traits::As;
/// Converts reference of struct to binary slice
#[inline(always)]
pub fn slicify<T>(value: &T) -> &[u8] {
let ptr = value as *const T as *const u8;
unsafe { core::slice::from_raw_parts(ptr, core::mem::size_of::<T>()) }
}
/// Converts reference of struct to binary slice
#[inline(always)]
pub unsafe fn slicify_mut<T>(value: &mut T) -> &mut [u8] {
let ptr = value as *mut T as *mut u8;
core::slice::from_raw_parts_mut(ptr, core::mem::size_of::<T>())
}
/// converts a non mutable reference into a mutable one
#[inline(always)]
pub unsafe fn mutify<T>(nr: &T) -> &mut T {
#[allow(invalid_reference_casting)]
&mut *(nr as *const T as *mut T)
}
/// converts a reference of any lifetime to 'static
#[inline(always)]
pub unsafe fn statify<'a, T>(nr: &'a T) -> &'static T {
&*(nr as *const T)
}
/// converts mutable a reference of any lifetime to 'static
#[inline(always)]
pub unsafe fn statify_mut<'a, T>(nr: &'a mut T) -> &'static mut T {
&mut *(nr as *mut T)
}
/// gets the distance between two references
pub fn distance(p1: impl As<usize>, p2: impl As<usize>) -> usize {
let (p1, p2) = (p1.cast(), p2.cast());
match p1.cmp(&p2) {
Ordering::Less => p2 - p1,
Ordering::Greater => p1 - p2,
Ordering::Equal => 0,
}
}

62
sub/core/src/ext/iter.rs Normal file
View File

@@ -0,0 +1,62 @@
pub trait IterExt: Iterator {
#[inline]
fn take_until<P>(self, predicate: P) -> TakeUntil<Self, P>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool,
{
TakeUntil::new(self, predicate)
}
}
impl<T: Iterator> IterExt for T {}
#[derive(Clone)]
pub struct TakeUntil<I, P> {
iter: I,
flag: bool,
predicate: P,
}
impl<I, P> TakeUntil<I, P> {
pub(in super) fn new(iter: I, predicate: P) -> TakeUntil<I, P> {
TakeUntil { iter, flag: false, predicate }
}
}
impl<I: Iterator, P> Iterator for TakeUntil<I, P>
where
P: FnMut(&I::Item) -> bool,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
if self.flag {
None
} else {
let x = self.iter.next()?;
if (self.predicate)(&x) {
Some(x)
} else {
self.flag = true;
Some(x)
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.flag {
(0, Some(0))
} else {
let (_, upper) = self.iter.size_hint();
(0, upper) // can't know a lower bound, due to the predicate
}
}
}

48
sub/core/src/ext/ptr.rs Normal file
View File

@@ -0,0 +1,48 @@
pub const fn null<T: Pointer>() -> T { T::NULL }
pub fn iterate<T: Pointer>(pointer: T) -> T::IterType {
pointer.into_iter()
}
pub trait Pointer {
type IterType;
const NULL: Self;
fn into_iter(self) -> Self::IterType;
}
pub struct PIter<T>(*const T);
pub struct PIterMut<T>(*mut T);
impl<T: 'static> Iterator for PIter<T> {
type Item = &'static T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let r = Some(&*self.0);
self.0 = self.0.offset(1isize);
r
}
}
}
impl<T: 'static> Iterator for PIterMut<T> {
type Item = &'static mut T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let r = Some(&mut *self.0);
self.0 = self.0.offset(1isize);
r
}
}
}
impl<T> Pointer for *const T {
type IterType = PIter<T>;
const NULL: Self = core::ptr::null();
fn into_iter(self) -> Self::IterType { PIter(self) }
}
impl<T> Pointer for *mut T {
type IterType = PIterMut<T>;
const NULL: Self = core::ptr::null_mut();
fn into_iter(self) -> Self::IterType { PIterMut(self) }
}

38
sub/core/src/ffi.rs Normal file
View File

@@ -0,0 +1,38 @@
/// appends zeroes to the end of the string and converts it into a pointer
/// useful for quick ffi
pub macro cstr($str:expr) {
concat!($str,"\0\0").as_ptr() as *const _
}
/// utility macro for inline c functions
///
/// | macro | rust |
/// |-----------|----------|
/// | ```cfn!( () -> usize )``` | ``` extern "C" fn() -> usize``` |
/// | ```cfn!( (usize) -> usize )``` | ``` extern "C" fn(usize) -> usize``` |
/// | ```cfn!( (usize) )``` | ``` extern "C" fn(usize)``` |
/// | ```cfn!( (u32, usize, usize) -> u32 )``` | ``` extern "C" fn(u32, usize, usize) -> u32``` |
pub macro cfn($str:expr) {
( ($($t:ty),*)) => {
extern "C" fn($( $t ),* )
};
( ($($t:ty),*) -> $r:ty) => {
extern "C" fn($( $t ),* ) -> $r
}
}
#[inline(always)]
pub fn _chain_helper<const N: usize>(address: usize, links: [usize;N]) -> usize {
links.iter().fold(address, |b,r| unsafe {*((b + *r) as *const usize)} )
}
#[allow(unused)]
use crate::cast_traits::As;
pub macro ptr_chain( $base:expr, $($link:expr),* ) {
_chain_helper(As::<usize>::cast($base), [
$(As::<usize>::cast($link)),*
])
}

76
sub/core/src/fnv1.rs Normal file
View File

@@ -0,0 +1,76 @@
const INITIAL_STATE: u64 = 0xcbf29ce484222325;
const PRIME: u64 = 0x100000001b3;
//noinspection DuplicatedCode
pub const fn hash(bytes: &[u8]) -> u64 {
let mut hash = INITIAL_STATE;
let mut i = 0;
while i < bytes.len() {
hash = hash ^ bytes[i] as u64;
hash = hash.wrapping_mul(PRIME);
i += 1;
}
hash
}
//noinspection DuplicatedCode
pub const fn hash32(bytes: &[u32]) -> u64 {
let mut hash = INITIAL_STATE;
let mut i = 0;
while i < bytes.len() {
hash = hash ^ bytes[i] as u64;
hash = hash.wrapping_mul(PRIME);
i += 1;
}
hash
}
//noinspection DuplicatedCode
#[inline(always)]
pub const fn hash64(bytes: &[u64]) -> u64 {
let mut hash = INITIAL_STATE;
let mut i = 0;
while i < bytes.len() {
hash = hash ^ bytes[i];
hash = hash.wrapping_mul(PRIME);
i += 1;
}
hash
}
//noinspection DuplicatedCode
#[inline(always)]
pub const fn hash_utf8(bytes: &[u8]) -> u64 {
let mut hash = INITIAL_STATE;
let mut i = 0;
while i < bytes.len() {
let char = match bytes[i] {
0x40..=0x5A => bytes[i] + 0x20,
_ => bytes[i],
} as u64;
hash = hash ^ (char);
hash = hash.wrapping_mul(PRIME);
i += 1;
}
hash
}
//noinspection DuplicatedCode
pub const fn hash_utf16(bytes: &[u16]) -> u64 {
let mut hash = INITIAL_STATE;
let mut i = 0;
while i < bytes.len() {
let char = match bytes[i] {
0x40..=0x5A => bytes[i] + 0x20,
_ => bytes[i],
} as u64;
hash = hash ^ (char);
hash = hash.wrapping_mul(PRIME);
i += 1;
}
hash
}

58
sub/core/src/lib.rs Normal file
View File

@@ -0,0 +1,58 @@
#![no_std] #![feature(decl_macro)] #![allow(unused)]
//
// Internal modules
//
pub mod cast_traits;
pub mod data;
pub mod arrays;
pub mod branching;
pub mod ffi;
pub mod ext {
pub mod iter;
pub mod ptr;
}
pub mod time;
pub mod fnv1;
pub mod pstruct;
//
// Export Preludes:
//
pub mod prelude {
pub use crate::cast_traits::{As, Upcast};
pub use crate::data::{
distance,
mutify,
slicify,
slicify_mut,
statify,
statify_mut
};
pub use crate::arrays::{
fill_with,
FixedVec,
};
pub use crate::branching::{
OnDrop,
Once,
once
};
pub use crate::ffi::{cfn, cstr, ptr_chain};
pub use crate::ext::iter::IterExt;
pub use crate::ext::ptr::{Pointer, iterate};
pub use crate::time::dur;
pub use crate::fnv1::*;
pub use crate::pstruct::struct_offset;
}
pub mod public {
pub use crate::ext::iter::TakeUntil;
pub use crate::ext::ptr::{PIter, PIterMut};
pub use crate::pstruct::VirtualOffset;
}

99
sub/core/src/pstruct.rs Normal file
View File

@@ -0,0 +1,99 @@
#![allow(unused)]
use core::fmt::{Debug, Display, Formatter, UpperHex};
use core::marker::PhantomData;
use core::mem::transmute;
use core::ops::{ControlFlow, Deref, DerefMut, Index, IndexMut};
pub struct VirtualOffset<T, const O: usize>(PhantomData<T>);
impl<T, const O: usize> VirtualOffset<T, O> {
#[inline(always)]
pub(crate) fn vo_as_ptr(&self) -> *mut T {
((self as *const _ as usize) + O) as *mut T
}
#[inline(always)]
pub(crate) fn offset() -> usize { O }
/// gets a ref to the underlying type
/// just an alias for the deref trait so it doesnt need to be imported
pub fn r#ref(&self) -> &T {
self.deref()
}
}
impl<T, const O: usize> Deref for VirtualOffset<T, O> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { transmute(((self as *const _ as usize) + O) as *const T)}
}
}
impl<T, const O: usize> DerefMut for VirtualOffset<T, O> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { transmute(((self as *mut _ as usize) + O) as *mut T)}
}
}
// ==============================
// Index
// ==============================
impl<I, T: Index<I>, const O: usize> Index<I> for VirtualOffset<T, O> {
type Output = T::Output;
fn index(&self, index: I) -> &Self::Output {
unsafe { &*self.vo_as_ptr() }.index(index)
}
}
impl<I, T: IndexMut<I>, const O: usize> IndexMut<I> for VirtualOffset<T, O> {
fn index_mut(&mut self, index: I) -> &mut Self::Output {
unsafe { &mut *self.vo_as_ptr() }.index_mut(index)
}
}
// ==============================
// Display + Debug
// ==============================
// Proxy the Display trait
impl<T: Display, const O: usize> Display for VirtualOffset<T, O> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.deref().fmt(f)
}
}
// Proxy the UpperHex trait
impl<T: UpperHex, const O: usize> UpperHex for VirtualOffset<T, O> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.deref().fmt(f)
}
}
// Proxy the Debug trait (in debug builds)
impl<T: Debug, const O: usize> Debug for VirtualOffset<T, O> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
self.deref().fmt(f)
}
}
// ==============================
// Macro
// ==============================
pub macro struct_offset {
($offset:literal, $type:ty) => {
$crate::VirtualOffset<$type, $offset>
}
}

46
sub/core/src/time.rs Normal file
View File

@@ -0,0 +1,46 @@
#![allow(unused)]
use core::time::Duration;
#[allow(nonstandard_style)]
pub mod __time_units {
pub mod units {
pub(super) type Milli = u64;
pub(super) type Second = u64;
pub(super) type Minute = u64;
pub(super) type Hour = u64;
pub(super) type Day = u64;
pub(super) type Week = u64;
}
pub mod plural {
use super::units::*;
pub const milliseconds : Milli = 1;
pub const seconds : Second = 1_000;
pub const hours : Hour = 60_000;
pub const minutes : Minute = 3_600_000;
pub const days : Day = 86_400_000;
pub const weeks : Week = 604_800_000;
}
pub mod singular {
use super::units::*;
pub const millisecond : Milli = super::plural::milliseconds;
pub const second : Second = super::plural::seconds;
pub const hour : Hour = super::plural::hours;
pub const minute : Minute = super::plural::minutes;
pub const day : Day = super::plural::days;
pub const week : Week = super::plural::weeks;
}
}
pub macro dur($($amount:tt $unit:ident $(,)?)+) {
core::time::Duration::from_millis(0u64 $( + ($crate::time::time_unit!( $amount, $unit)) )+ )
}
macro time_unit {
(1, $unit:ident) => { $crate::time::__time_units::singular::$unit },
($number:literal, $unit:ident) => { $number * $crate::time::__time_units::plural::$unit }
}