commit
d8af6e37a2
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
*~
|
@ -0,0 +1,25 @@
|
|||||||
|
[package]
|
||||||
|
name = "malloc-array"
|
||||||
|
description = "libc heap array allocator"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Avril <flanchan@cumallover.me>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "GPL v3"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["zst_noalloc"]
|
||||||
|
|
||||||
|
# Assume Rust will free things allocated with malloc() properly.
|
||||||
|
assume_libc = []
|
||||||
|
|
||||||
|
# Do not allocate for ZSTs
|
||||||
|
zst_noalloc = []
|
||||||
|
|
||||||
|
# Use jemalloc instead of libc malloc
|
||||||
|
jemalloc = ["jemalloc-sys"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = "0.2"
|
||||||
|
jemalloc-sys = { version = "0.3", optional = true }
|
@ -0,0 +1,109 @@
|
|||||||
|
use std::{
|
||||||
|
ffi::c_void,
|
||||||
|
error,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
ptr::{self,VoidPointer,},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error;
|
||||||
|
|
||||||
|
impl error::Error for Error{}
|
||||||
|
impl fmt::Display for Error
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "Allocation failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn malloc_internal(sz: libc::size_t) -> *mut c_void
|
||||||
|
{
|
||||||
|
#[cfg(feature="jemalloc")]
|
||||||
|
return jemalloc_sys::malloc(sz);
|
||||||
|
#[cfg(not(feature="jemalloc"))]
|
||||||
|
return libc::malloc(sz);
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
unsafe fn calloc_internal(nm: libc::size_t, sz: libc::size_t) -> *mut c_void
|
||||||
|
{
|
||||||
|
#[cfg(feature="jemalloc")]
|
||||||
|
return jemalloc_sys::calloc(nm,sz);
|
||||||
|
#[cfg(not(feature="jemalloc"))]
|
||||||
|
return libc::calloc(nm,sz);
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
unsafe fn free_internal(ptr: *mut c_void)
|
||||||
|
{
|
||||||
|
#[cfg(feature="jemalloc")]
|
||||||
|
return jemalloc_sys::free(ptr);
|
||||||
|
#[cfg(not(feature="jemalloc"))]
|
||||||
|
return libc::free(ptr);
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
unsafe fn realloc_internal(ptr: *mut c_void, sz: libc::size_t) -> *mut c_void
|
||||||
|
{
|
||||||
|
#[cfg(feature="jemalloc")]
|
||||||
|
return jemalloc_sys::realloc(ptr,sz);
|
||||||
|
#[cfg(not(feature="jemalloc"))]
|
||||||
|
return libc::realloc(ptr,sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NULL_PTR: *mut c_void = 0 as *mut c_void;
|
||||||
|
|
||||||
|
pub unsafe fn malloc(sz: usize) -> Result<VoidPointer,Error>
|
||||||
|
{
|
||||||
|
#[cfg(feature="zst_noalloc")]
|
||||||
|
if sz == 0 {
|
||||||
|
return Ok(ptr::NULL_PTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
match malloc_internal(sz as libc::size_t)
|
||||||
|
{
|
||||||
|
null if null == NULL_PTR => Err(Error),
|
||||||
|
ptr => Ok(ptr as VoidPointer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn calloc(nm: usize, sz: usize) -> Result<VoidPointer, Error>
|
||||||
|
{
|
||||||
|
#[cfg(feature="zst_noalloc")]
|
||||||
|
if (nm*sz) == 0 {
|
||||||
|
return Ok(ptr::NULL_PTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
match calloc_internal(nm as libc::size_t, sz as libc::size_t)
|
||||||
|
{
|
||||||
|
null if null == NULL_PTR => Err(Error),
|
||||||
|
ptr => Ok(ptr as VoidPointer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn free(ptr: VoidPointer)
|
||||||
|
{
|
||||||
|
if ptr != crate::ptr::NULL_PTR {
|
||||||
|
free_internal(ptr as *mut c_void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn realloc(ptr: VoidPointer, sz: usize) -> Result<VoidPointer, Error>
|
||||||
|
{
|
||||||
|
#[cfg(feature="zst_noalloc")]
|
||||||
|
if sz == 0 {
|
||||||
|
free(ptr);
|
||||||
|
return Ok(crate::ptr::NULL_PTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ptr == crate::ptr::NULL_PTR {
|
||||||
|
return malloc(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
match realloc_internal(ptr as *mut c_void, sz as libc::size_t)
|
||||||
|
{
|
||||||
|
null if null == NULL_PTR => Err(Error),
|
||||||
|
ptr => Ok(ptr as VoidPointer),
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
mem::{
|
||||||
|
replace,
|
||||||
|
MaybeUninit,
|
||||||
|
forget,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use ptr::{
|
||||||
|
VoidPointer,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct IntoIter<T>
|
||||||
|
{
|
||||||
|
start: *mut T,
|
||||||
|
current: *mut T,
|
||||||
|
sz: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIter<T>
|
||||||
|
{
|
||||||
|
fn current_offset(&self) -> usize
|
||||||
|
{
|
||||||
|
(self.current as usize) - (self.start as usize)
|
||||||
|
}
|
||||||
|
fn free_if_needed(&mut self)
|
||||||
|
{
|
||||||
|
if self.start != ptr::null() && self.current_offset() >= self.sz {
|
||||||
|
unsafe {
|
||||||
|
alloc::free(self.start as VoidPointer);
|
||||||
|
}
|
||||||
|
self.start = ptr::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Iterator for IntoIter<T>
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>
|
||||||
|
{
|
||||||
|
let output = if self.current_offset() >= self.sz {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
let output = replace(&mut (*self.current), MaybeUninit::zeroed().assume_init());
|
||||||
|
self.current = self.current.offset(1);
|
||||||
|
Some(output)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.free_if_needed();
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIterator for HeapArray<T>
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter
|
||||||
|
{
|
||||||
|
let output = Self::IntoIter {
|
||||||
|
start: self.ptr,
|
||||||
|
current: self.ptr,
|
||||||
|
sz: self.len(),
|
||||||
|
};
|
||||||
|
forget(self);
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,377 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
#[cfg(feature="jemalloc")]
|
||||||
|
extern crate jemalloc_sys;
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn as_slice() {
|
||||||
|
let heap = heap![unsafe 0, 1, 2, 3u8];
|
||||||
|
|
||||||
|
assert_eq!(heap.as_slice(), [0,1,2,3u8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_trivial_type() {
|
||||||
|
let heap = heap!["test one".to_owned(), "test two".to_owned()];
|
||||||
|
|
||||||
|
assert_eq!(heap.as_slice(), ["test one", "test two"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn zero_size() {
|
||||||
|
let heap: HeapArray<u8> = heap![];
|
||||||
|
let heap_zst: HeapArray<()> = heap![(); 3];
|
||||||
|
|
||||||
|
assert_eq!(&heap.as_slice(), &[]);
|
||||||
|
assert_eq!(&heap_zst.as_slice(), &[(),(),()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn into_iter() {
|
||||||
|
let primitive = heap![1,3,5,7,9u32];
|
||||||
|
|
||||||
|
for x in primitive.into_iter()
|
||||||
|
{
|
||||||
|
assert_eq!(x % 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let non = heap!["string one".to_owned(), "string two".to_owned()];
|
||||||
|
|
||||||
|
for x in non.into_iter()
|
||||||
|
{
|
||||||
|
assert_eq!(&x[..6], "string");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod ptr;
|
||||||
|
mod alloc;
|
||||||
|
mod reinterpret;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ops::{
|
||||||
|
Drop,
|
||||||
|
Index,IndexMut,
|
||||||
|
Deref,DerefMut,
|
||||||
|
},
|
||||||
|
borrow::{
|
||||||
|
Borrow,BorrowMut,
|
||||||
|
},
|
||||||
|
slice::{
|
||||||
|
self,
|
||||||
|
SliceIndex,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
ptr::{
|
||||||
|
VoidPointer,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
/// `vec![]`-like macro for creating `HeapArray<T>` instances.
|
||||||
|
///
|
||||||
|
/// Provices methods for creating safly accessable arrays using `malloc()` with a `Vec<T>` like interface.
|
||||||
|
/// Also provides methods of optimising deallocations.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
///
|
||||||
|
/// Works like array definitions `[type; size]`, and like the `vec![]` macro `[value; size]`. Prepend the statement with `unsafe` (`[unsafe type|value; size]`) to prevent potentially redundant `drop()` calls.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use malloc_array::{heap, HeapArray};
|
||||||
|
/// let ints = heap![unsafe 4u32; 32]; // Creates a 32 element `u32` array with each element set to `4`.
|
||||||
|
/// let ints = heap![unsafe u32; 32]; // Creates an uninitialised 32 element `u32` array.
|
||||||
|
/// let ints = heap![u32; 32]; // Same as above, except when `ints` is dropped, each element will be also dropped redundantly.
|
||||||
|
/// let strings = heap!["string one".to_owned(), "string two".to_owned()]; //Creates a 2 element string array.
|
||||||
|
/// let strings = heap![unsafe "memory".to_owned(), "leak".to_owned()]; //Same as above, except `drop()` will not be called on the 2 strings, potentially causing a memory leak.
|
||||||
|
/// let strings: HeapArray<u8> = heap![]; //Creates an empty `u8` array.
|
||||||
|
/// ```
|
||||||
|
macro_rules! heap {
|
||||||
|
() => {
|
||||||
|
$crate::HeapArray::new_uninit(0)
|
||||||
|
};
|
||||||
|
(@) => (0usize);
|
||||||
|
(@ $x:tt $($xs:tt)* ) => (1usize + $crate::heap!(@ $($xs)*));
|
||||||
|
|
||||||
|
(unsafe $($xs:tt)*) => {
|
||||||
|
{
|
||||||
|
#[allow(unused_unsafe)]
|
||||||
|
unsafe {
|
||||||
|
let mut output = $crate::heap!($($xs)*);
|
||||||
|
output.drop_check = false;
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($type:ty; $number:expr) => {
|
||||||
|
{
|
||||||
|
$crate::HeapArray::<$type>::new($number)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($value:expr; $number:expr) => {
|
||||||
|
{
|
||||||
|
let num = $number;
|
||||||
|
let mut ha = $crate::HeapArray::new_uninit(num);
|
||||||
|
|
||||||
|
for x in 0..num {
|
||||||
|
ha[x] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($($n:expr),*) => {
|
||||||
|
{
|
||||||
|
let mut ha = $crate::HeapArray::new_uninit($crate::heap!(@ $($n)*));
|
||||||
|
{
|
||||||
|
let fp = 0;
|
||||||
|
$(
|
||||||
|
let fp = fp + 1;
|
||||||
|
ha[fp-1] = $n;
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
ha
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HeapArray<T> {
|
||||||
|
ptr: *mut T,
|
||||||
|
size: usize,
|
||||||
|
|
||||||
|
/// Call `drop()` on sub-elements when `drop`ping the array. This is not needed for types that implement `Copy`.
|
||||||
|
pub drop_check: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> HeapArray<T>
|
||||||
|
{
|
||||||
|
pub fn len_bytes(&self) -> usize
|
||||||
|
{
|
||||||
|
Self::element_size() * self.size
|
||||||
|
}
|
||||||
|
pub fn len(&self) -> usize
|
||||||
|
{
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn element_size() -> usize
|
||||||
|
{
|
||||||
|
std::mem::size_of::<T>()
|
||||||
|
}
|
||||||
|
const fn is_single() -> bool
|
||||||
|
{
|
||||||
|
std::mem::size_of::<T>() == 1
|
||||||
|
}
|
||||||
|
pub fn new(size: usize) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
ptr: unsafe{alloc::calloc(size, Self::element_size()).expect("calloc()")} as *mut T,
|
||||||
|
size,
|
||||||
|
drop_check: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new_uninit(size: usize) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
ptr: unsafe{alloc::malloc(size * Self::element_size()).expect("malloc()")} as *mut T,
|
||||||
|
size,
|
||||||
|
drop_check: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn new_repeat(initial: T, size: usize) -> Self
|
||||||
|
where T: Copy
|
||||||
|
{
|
||||||
|
let this = Self::new_uninit(size);
|
||||||
|
if size > 0 {
|
||||||
|
if Self::is_single() {
|
||||||
|
unsafe {
|
||||||
|
ptr::memset(this.ptr as *mut u8, reinterpret::bytes(initial), this.len_bytes());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
for x in 0..size {
|
||||||
|
*this.ptr.offset(x as isize) = initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this
|
||||||
|
}
|
||||||
|
pub fn new_range<U>(initial: U, size: usize) -> Self
|
||||||
|
where T: Copy,
|
||||||
|
U: AsRef<[T]>
|
||||||
|
{
|
||||||
|
let initial = initial.as_ref();
|
||||||
|
if size > 0 {
|
||||||
|
if initial.len() == 1 {
|
||||||
|
Self::new_repeat(initial[0], size)
|
||||||
|
} else {
|
||||||
|
let this = Self::new_uninit(size);
|
||||||
|
unsafe {
|
||||||
|
for x in 0..size {
|
||||||
|
*this.ptr.offset(x as isize) = initial[x % initial.len()];
|
||||||
|
}
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Self::new_uninit(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &[T]
|
||||||
|
{
|
||||||
|
unsafe{slice::from_raw_parts(self.ptr, self.size)}
|
||||||
|
}
|
||||||
|
pub fn as_slice_mut(&mut self) -> &mut [T]
|
||||||
|
{
|
||||||
|
unsafe{slice::from_raw_parts_mut(self.ptr, self.size)}
|
||||||
|
}
|
||||||
|
pub fn as_ptr(&self) -> *const T
|
||||||
|
{
|
||||||
|
self.ptr as *const T
|
||||||
|
}
|
||||||
|
pub fn as_ptr_mut(&mut self) -> *mut T
|
||||||
|
{
|
||||||
|
self.ptr
|
||||||
|
}
|
||||||
|
pub fn memory(&self) -> &[u8]
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
slice::from_raw_parts(self.ptr as *const u8, self.len_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn memory_mut(&mut self) -> &mut [u8]
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
slice::from_raw_parts_mut(self.ptr as *mut u8, self.len_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
pub fn into_boxed_slice(mut self) -> Box<[T]>
|
||||||
|
{
|
||||||
|
#[cfg(feature="assume_libc")]
|
||||||
|
unsafe {
|
||||||
|
let bx = Box::from_raw(self.as_slice_mut() as *mut [T]);
|
||||||
|
std::mem::forget(self);
|
||||||
|
bx
|
||||||
|
}
|
||||||
|
#[cfg(not(feature="assume_libc"))]
|
||||||
|
{
|
||||||
|
let vec = Vec::from(self);
|
||||||
|
return vec.into_boxed_slice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, I> Index<I> for HeapArray<T>
|
||||||
|
where I: SliceIndex<[T]>
|
||||||
|
{
|
||||||
|
type Output = <I as SliceIndex<[T]>>::Output;
|
||||||
|
fn index(&self, index: I) -> &Self::Output
|
||||||
|
{
|
||||||
|
&self.as_slice()[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T, I> IndexMut<I> for HeapArray<T>
|
||||||
|
where I: SliceIndex<[T]>
|
||||||
|
{
|
||||||
|
fn index_mut(&mut self, index: I) -> &mut <Self as Index<I>>::Output
|
||||||
|
{
|
||||||
|
&mut self.as_slice_mut()[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for HeapArray<T>
|
||||||
|
{
|
||||||
|
fn drop(&mut self)
|
||||||
|
{
|
||||||
|
if self.ptr != ptr::null::<T>() {
|
||||||
|
if self.drop_check {
|
||||||
|
for i in 0..self.size
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
drop(ptr::take(self.ptr.offset(i as isize)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe{alloc::free(self.ptr as VoidPointer)};
|
||||||
|
self.ptr = ptr::null::<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AsMut<[T]> for HeapArray<T>
|
||||||
|
{
|
||||||
|
fn as_mut(&mut self) -> &mut [T]
|
||||||
|
{
|
||||||
|
self.as_slice_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> AsRef<[T]> for HeapArray<T>
|
||||||
|
{
|
||||||
|
fn as_ref(&self) -> &[T]
|
||||||
|
{
|
||||||
|
self.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for HeapArray<T>
|
||||||
|
{
|
||||||
|
type Target = [T];
|
||||||
|
fn deref(&self) -> &Self::Target
|
||||||
|
{
|
||||||
|
self.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> DerefMut for HeapArray<T>
|
||||||
|
{
|
||||||
|
fn deref_mut(&mut self) -> &mut <Self as Deref>::Target
|
||||||
|
{
|
||||||
|
self.as_slice_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Borrow<[T]> for HeapArray<T>
|
||||||
|
{
|
||||||
|
fn borrow(&self) -> &[T]
|
||||||
|
{
|
||||||
|
self.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> BorrowMut<[T]> for HeapArray<T>
|
||||||
|
{
|
||||||
|
fn borrow_mut(&mut self) -> &mut [T]
|
||||||
|
{
|
||||||
|
self.as_slice_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<HeapArray<T>> for Vec<T>
|
||||||
|
{
|
||||||
|
fn from(ha: HeapArray<T>) -> Self
|
||||||
|
{
|
||||||
|
let mut output = Vec::with_capacity(ha.len());
|
||||||
|
for item in ha.into_iter()
|
||||||
|
{
|
||||||
|
output.push(item);
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod iter;
|
||||||
|
pub use iter::*;
|
@ -0,0 +1,35 @@
|
|||||||
|
use std::{
|
||||||
|
ffi::c_void,
|
||||||
|
mem::{
|
||||||
|
self,
|
||||||
|
MaybeUninit,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use libc::{
|
||||||
|
size_t,
|
||||||
|
c_int,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type VoidPointer = *mut ();
|
||||||
|
pub type ConstVoidPointer = *const ();
|
||||||
|
|
||||||
|
pub const NULL_PTR: VoidPointer = 0 as VoidPointer;
|
||||||
|
|
||||||
|
pub fn null<T>() -> *mut T
|
||||||
|
{
|
||||||
|
NULL_PTR as *mut T
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn memset(ptr: *mut u8, value: u8, length: usize)
|
||||||
|
{
|
||||||
|
libc::memset(ptr as *mut c_void, value as c_int, length as size_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn replace<T>(ptr: *mut T, value: T) -> T
|
||||||
|
{
|
||||||
|
mem::replace(&mut *ptr, value)
|
||||||
|
}
|
||||||
|
pub unsafe fn take<T>(ptr: *mut T) -> T
|
||||||
|
{
|
||||||
|
mem::replace(&mut *ptr, MaybeUninit::zeroed().assume_init())
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
use std::{
|
||||||
|
mem::size_of,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn bytes<T,U>(input: T) -> U
|
||||||
|
where T: Copy,
|
||||||
|
U: Copy
|
||||||
|
{
|
||||||
|
//let _array: [(); size_of::<T>() - size_of::<U>()]; // rust is silly....
|
||||||
|
if size_of::<U>() < size_of::<T>() {
|
||||||
|
panic!("reinterpret: Expected at least {} bytes, got {}.", size_of::<T>(), size_of::<U>());
|
||||||
|
}
|
||||||
|
return *((&input as *const T) as *const U)
|
||||||
|
}
|
Loading…
Reference in new issue