1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
#![warn(rust_2018_idioms, clippy::dbg_macro, clippy::print_stdout)]
/*!
Alloc related items for [phper](https://crates.io/crates/phper).
## License
[Unlicense](https://github.com/jmjoy/phper/blob/master/LICENSE).
*/
use phper_sys::*;
use std::{
convert::TryInto,
mem::{forget, size_of},
ops::{Deref, DerefMut},
};
// TODO Add ERc, for refcounted type.
/// The item which can be placed into container [EBox].
pub trait EAllocatable {
/// The method to free the heap allocated by `emalloc`, should call `efree` at the end.
fn free(ptr: *mut Self) {
unsafe {
_efree(ptr.cast());
}
}
}
/// The Box which use php `emalloc` and `efree` to manage memory.
///
/// TODO now feature `allocator_api` is still unstable, implement myself, use Box<T, Alloc> later.
pub struct EBox<T: EAllocatable> {
ptr: *mut T,
}
impl<T: EAllocatable> EBox<T> {
/// Allocates heap memory using `emalloc` then places `x` into it.
///
/// # Panic
///
/// Panic if `size_of::<T>()` equals zero.
pub fn new(x: T) -> Self {
unsafe {
assert_ne!(size_of::<T>(), 0);
let ptr: *mut T = _emalloc(size_of::<T>().try_into().unwrap()).cast();
ptr.write(x);
Self { ptr }
}
}
/// Constructs from a raw pointer.
pub unsafe fn from_raw(raw: *mut T) -> Self {
Self { ptr: raw }
}
/// Consumes and returning a wrapped raw pointer.
///
/// Will leak memory.
pub fn into_raw(b: EBox<T>) -> *mut T {
let ptr = b.ptr;
forget(b);
ptr
}
}
impl<T: EAllocatable> Deref for EBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.as_ref().unwrap() }
}
}
impl<T: EAllocatable> DerefMut for EBox<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.as_mut().unwrap() }
}
}
impl<T: EAllocatable> Drop for EBox<T> {
fn drop(&mut self) {
<T>::free(self.ptr);
}
}
unsafe impl<T: EAllocatable> Send for EBox<T> {}
// TODO Write Erc for gc_refcounted holding types.
// pub trait ERcAble {
// // Increment the reference count;
// fn incr(&mut self);
//
// /// Decrement the reference count and return old count.
// fn decr(&mut self) -> usize;
// }
//
// pub struct ERc<T> {
// value: T,
// }
//
// impl<T> ERc<T> {
// pub fn new(value: T) -> Self {
// Self { value }
// }
// }