phper_alloc/
lib.rs

1// Copyright (c) 2022 PHPER Framework Team
2// PHPER is licensed under Mulan PSL v2.
3// You can use this software according to the terms and conditions of the Mulan
4// PSL v2. You may obtain a copy of Mulan PSL v2 at:
5//          http://license.coscl.org.cn/MulanPSL2
6// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
7// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9// See the Mulan PSL v2 for more details.
10
11#![warn(rust_2018_idioms, missing_docs)]
12#![warn(clippy::dbg_macro, clippy::print_stdout)]
13#![doc = include_str!("../README.md")]
14
15#[macro_use]
16mod macros;
17
18use phper_sys::*;
19use std::{
20    borrow::Borrow,
21    mem::{ManuallyDrop, size_of},
22    ops::{Deref, DerefMut},
23};
24
25/// The Box which use php `emalloc` and `efree` to manage memory.
26///
27/// TODO Now feature `allocator_api` is still unstable, implement myself, use
28/// Box<T, Alloc> later.
29pub struct EBox<T> {
30    ptr: *mut T,
31}
32
33impl<T> EBox<T> {
34    /// Allocates heap memory using `emalloc` then places `x` into it.
35    ///
36    /// # Panic
37    ///
38    /// Panic if `size_of::<T>()` equals zero.
39    #[allow(clippy::useless_conversion)]
40    pub fn new(x: T) -> Self {
41        unsafe {
42            assert_ne!(size_of::<T>(), 0);
43            let ptr: *mut T = phper_emalloc(size_of::<T>().try_into().unwrap()).cast();
44            // TODO Deal with ptr is zero, when memory limit is reached.
45            ptr.write(x);
46            Self { ptr }
47        }
48    }
49
50    /// Constructs from a raw pointer.
51    ///
52    /// # Safety
53    ///
54    /// Make sure the pointer is from `into_raw`, or created from `emalloc`.
55    pub unsafe fn from_raw(raw: *mut T) -> Self {
56        Self { ptr: raw }
57    }
58
59    /// Consumes and returning a wrapped raw pointer.
60    ///
61    /// Will leak memory.
62    pub fn into_raw(b: EBox<T>) -> *mut T {
63        ManuallyDrop::new(b).ptr
64    }
65
66    /// Consumes the `EBox`, returning the wrapped value.
67    pub fn into_inner(self) -> T {
68        unsafe { self.ptr.read() }
69    }
70}
71
72impl<T> Deref for EBox<T> {
73    type Target = T;
74
75    fn deref(&self) -> &Self::Target {
76        unsafe { self.ptr.as_ref().unwrap() }
77    }
78}
79
80impl<T> DerefMut for EBox<T> {
81    fn deref_mut(&mut self) -> &mut Self::Target {
82        unsafe { self.ptr.as_mut().unwrap() }
83    }
84}
85
86impl<T> Drop for EBox<T> {
87    fn drop(&mut self) {
88        unsafe {
89            self.ptr.drop_in_place();
90            phper_efree(self.ptr.cast());
91        }
92    }
93}
94
95/// Duplicate an object without deep copy, but to only add the refcount, for php
96/// refcount struct.
97pub trait ToRefOwned {
98    /// The resulting type after obtaining ownership.
99    type Owned: Borrow<Self>;
100
101    /// Creates owned data from borrowed data, by increasing refcount.
102    fn to_ref_owned(&mut self) -> Self::Owned;
103}
104
105/// Duplicate an object without deep copy, but to only add the refcount, for php
106/// refcount struct.
107pub trait RefClone {
108    /// Returns a refcount value with same reference of the value.
109    fn ref_clone(&mut self) -> Self;
110}