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}