use std::ptr::{copy_nonoverlapping, null_mut};
use crate::{
header::{AllocationHeader, HEADER_SIZE},
ReallocationError,
};
pub unsafe fn realloc(ptr: *mut u8, new_size: usize) -> Result<*mut u8, ReallocationError> {
if ptr.is_null() {
return Ok(crate::alloc(new_size)?);
}
if !(ptr as usize).is_multiple_of(HEADER_SIZE) {
return Err(ReallocationError::ImproperAlignment);
}
let header_ptr: *mut AllocationHeader = ptr.sub(HEADER_SIZE).cast();
if !header_ptr.is_aligned() {
return Err(ReallocationError::ImproperAlignment);
}
if (*header_ptr).is_marked_as_free() {
return Err(ReallocationError::MarkerFree);
}
if !(*header_ptr).is_marked_as_used() {
return Err(ReallocationError::MarkerCorrupted);
}
if new_size == 0 {
crate::free(ptr)?;
return Ok(null_mut());
}
let Ok(new_ptr) = crate::alloc(new_size) else {
return Err(ReallocationError::NewAllocationFailed(ptr));
};
let memset_len = (*header_ptr)
.get_size()
.saturating_sub(HEADER_SIZE)
.min(new_size);
copy_nonoverlapping(ptr, new_ptr, memset_len);
match crate::free(ptr) {
Ok(()) => {}
Err(err) => {
crate::free(new_ptr)?;
Err(err)?;
}
}
Ok(new_ptr)
}