#![expect(
unsafe_op_in_unsafe_fn,
reason = "Array requires unsafe code in some places"
)]
use std::alloc;
use std::ops::{Deref, DerefMut, Index, IndexMut};
#[derive(Debug, thiserror::Error)]
pub enum ArrayCreationError {
#[error("allocation error: {0}")]
AllocationError(String),
#[error("layout error: {0}")]
LayoutError(#[from] alloc::LayoutError),
}
pub struct Array<T> {
ptr: *mut T,
size: usize,
}
impl<T> Array<T> {
pub fn new(size: usize) -> Result<Self, ArrayCreationError> {
unsafe {
let layout = alloc::Layout::array::<T>(size)?;
let ptr = alloc::alloc(layout) as *mut T;
if ptr.is_null() {
return Err(ArrayCreationError::AllocationError(
"null pointer".to_owned(),
));
}
Ok(Self { ptr, size })
}
}
#[must_use]
pub const fn size(&self) -> usize {
self.size
}
#[must_use]
pub const fn as_ptr(&self) -> *const T {
self.ptr
}
#[must_use]
pub const fn as_mut_ptr(&self) -> *mut T {
self.ptr
}
pub fn set(&mut self, index: usize, value: T) {
if index >= self.size {
panic!("index out of bounds");
}
unsafe { *(self.ptr.add(index)) = value }
}
#[must_use]
pub const fn get(&self, index: usize) -> Option<&T> {
if index >= self.size {
return None;
}
unsafe { Some(&(*(self.ptr.add(index)))) }
}
#[must_use]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if index >= self.size {
return None;
}
unsafe { Some(&mut (*(self.ptr.add(index)))) }
}
#[must_use]
pub const unsafe fn get_ptr(&self, index: usize) -> *const T {
self.ptr.add(index) as *const T
}
#[must_use]
pub unsafe fn get_ptr_mut(&mut self, index: usize) -> *mut T {
self.ptr.add(index)
}
#[must_use]
pub fn iter(&self) -> iter::Iter<'_, T> {
iter::Iter::new(self)
}
#[must_use]
pub fn iter_mut(&mut self) -> iter::IterMut<'_, T> {
iter::IterMut::new(self)
}
}
impl<T> Drop for Array<T> {
fn drop(&mut self) {
unsafe {
self.ptr.drop_in_place();
}
}
}
impl<T> Deref for Array<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.ptr, self.size) }
}
}
impl<T> DerefMut for Array<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::slice::from_raw_parts_mut(self.ptr, self.size) }
}
}
impl<T> AsRef<[T]> for Array<T> {
fn as_ref(&self) -> &[T] {
self
}
}
impl<T> AsMut<[T]> for Array<T> {
fn as_mut(&mut self) -> &mut [T] {
&mut *self
}
}
impl std::io::Write for Array<u8> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut index = 0;
for b in buf {
self[index] = *b;
index += 1;
}
Ok(index + 1)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl<T> Index<usize> for Array<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).expect("index out of bounds")
}
}
impl<T> IndexMut<usize> for Array<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index).expect("index out of bounds")
}
}
impl<T: Clone> Clone for Array<T> {
fn clone(&self) -> Self {
let mut array = Array::new(self.size).expect("allocation failed");
for (i, v) in self.iter().enumerate() {
array[i] = v.clone();
}
array
}
}
impl<T> IntoIterator for Array<T> {
type Item = T;
type IntoIter = iter::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
iter::IntoIter::new(self)
}
}
impl<'a, T> IntoIterator for &'a Array<T> {
type Item = &'a T;
type IntoIter = iter::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut Array<T> {
type Item = &'a mut T;
type IntoIter = iter::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub mod iter {
use super::Array;
use std::marker::PhantomData;
pub struct Iter<'a, T> {
_marker: PhantomData<&'a T>,
ptr: *const T,
end: *const T,
}
impl<'a, T> Iter<'a, T> {
pub(crate) fn new(array: &'a Array<T>) -> Self {
let ptr = array.ptr;
Self {
_marker: PhantomData,
ptr,
end: unsafe { ptr.add(array.size) },
}
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.ptr == self.end {
None
} else {
unsafe {
let ptr = self.ptr;
self.ptr = self.ptr.add(1);
Some(&*ptr)
}
}
}
}
pub struct IterMut<'a, T> {
_marker: PhantomData<&'a T>,
ptr: *mut T,
end: *mut T,
}
impl<'a, T> IterMut<'a, T> {
pub(crate) fn new(array: &'a Array<T>) -> Self {
let ptr = array.ptr;
Self {
_marker: PhantomData,
ptr,
end: unsafe { ptr.add(array.size) },
}
}
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
if self.ptr == self.end {
None
} else {
unsafe {
let ptr = self.ptr;
self.ptr = self.ptr.add(1);
Some(&mut *ptr)
}
}
}
}
pub struct IntoIter<T> {
_array: Array<T>,
ptr: *const T,
end: *const T,
}
impl<T> IntoIter<T> {
pub(crate) fn new(array: Array<T>) -> Self {
unsafe {
let ptr = array.ptr.cast_const();
let end = ptr.add(array.size);
Self {
_array: array,
ptr,
end,
}
}
}
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.ptr == self.end {
None
} else {
unsafe {
let ptr = self.ptr;
self.ptr = self.ptr.add(1);
Some(ptr.read())
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn array_basics() {
let mut array = Array::new(5).expect("failed to allocate");
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
array[4] = 5;
for (i, v) in array.iter().enumerate() {
match i {
0 => assert_eq!(*v, 1),
1 => assert_eq!(*v, 2),
2 => assert_eq!(*v, 3),
3 => assert_eq!(*v, 4),
4 => assert_eq!(*v, 5),
_ => unreachable!(),
}
}
}
}