Skip to content

Commit a5876e4

Browse files
committed
Add ZendString and Array apis, add Throwable macro attribute.
1 parent 479ae41 commit a5876e4

File tree

15 files changed

+212
-90
lines changed

15 files changed

+212
-90
lines changed

examples/http-client/src/errors.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use phper::{
2-
classes::{ClassEntry, DynamicClass, StatelessClassEntry},
3-
errors::Throwable,
4-
};
1+
use phper::classes::{ClassEntry, DynamicClass};
52

63
const EXCEPTION_CLASS_NAME: &'static str = "HttpClient\\HttpClientException";
74

phper-macros/src/derives.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use proc_macro::TokenStream;
22
use proc_macro2::TokenStream as TokenStream2;
33
use quote::quote;
4-
use syn::{Attribute, Data, DeriveInput, Expr, Fields, Meta, MetaNameValue};
4+
use syn::{Attribute, Data, DeriveInput, Expr, Fields};
55

66
pub(crate) fn derive_throwable(input: DeriveInput) -> syn::Result<TokenStream> {
77
let crate_ident = parse_throwable_crate_ident(&input);

phper-sys/php_wrapper.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,18 @@ void phper_zend_string_release(zend_string *s) {
7474
return zend_string_release(s);
7575
}
7676

77-
zval *phper_zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData) {
77+
zval* phper_zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData) {
7878
return zend_hash_str_update(ht, key, len, pData);
7979
}
8080

8181
zval* phper_zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData) {
8282
return zend_hash_index_update(ht, h, pData);
8383
}
8484

85+
zval* phper_zend_hash_next_index_insert(HashTable *ht, zval *pData) {
86+
return zend_hash_next_index_insert(ht, pData);
87+
}
88+
8589
void phper_array_init(zval *arg) {
8690
array_init(arg);
8791
}
@@ -161,6 +165,6 @@ bool phper_zend_hash_index_exists(const HashTable *ht, zend_ulong h) {
161165
return zend_hash_index_exists(ht, h) != 0;
162166
}
163167

164-
void phper_zval_dtor(zval *zval_ptr) {
165-
return zval_dtor(zval_ptr);
166-
}
168+
void phper_zval_ptr_dtor_nogc(zval *zval_ptr) {
169+
zval_ptr_dtor_nogc(zval_ptr);
170+
}

phper-sys/php_wrapper.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ zend_string *phper_zend_string_init(const char *str, size_t len, int persistent)
3333
zend_string *phper_zend_string_alloc(size_t len, int persistent);
3434
void phper_zend_string_release(zend_string *s);
3535

36-
zval *phper_zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData);
36+
zval* phper_zend_hash_str_update(HashTable *ht, const char *key, size_t len, zval *pData);
3737
zval* phper_zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData);
38+
zval* phper_zend_hash_next_index_insert(HashTable *ht, zval *pData);
3839

3940
void phper_array_init(zval *arg);
4041
void *phper_zend_hash_str_find_ptr(const HashTable *ht, const char *str, size_t len);
@@ -56,6 +57,6 @@ bool phper_call_user_function(HashTable *function_table, zval *object, zval *fun
5657
bool phper_zend_hash_str_exists(const HashTable *ht, const char *str, size_t len);
5758
bool phper_zend_hash_index_exists(const HashTable *ht, zend_ulong h);
5859

59-
void phper_zval_dtor(zval *zval_ptr);
60+
void phper_zval_ptr_dtor_nogc(zval *zval_ptr);
6061

6162
#endif //PHPER_PHP_WRAPPER_H

phper/src/arrays.rs

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,22 @@ use crate::{
66
sys::*,
77
values::Val,
88
};
9-
use std::{borrow::Cow, mem::zeroed};
9+
use derive_more::From;
10+
use std::mem::zeroed;
1011

1112
/// Key for [Array].
12-
#[derive(Debug, Clone, PartialEq)]
13+
#[derive(Debug, Clone, PartialEq, From)]
1314
pub enum Key<'a> {
1415
Index(u64),
15-
Str(Cow<'a, str>),
16+
Str(&'a str),
1617
}
1718

18-
impl From<u64> for Key<'_> {
19-
fn from(i: u64) -> Self {
20-
Key::Index(i)
21-
}
22-
}
23-
24-
impl<'a> From<&'a str> for Key<'a> {
25-
fn from(s: &'a str) -> Self {
26-
Key::Str(Cow::Borrowed(s))
27-
}
28-
}
29-
30-
impl From<String> for Key<'_> {
31-
fn from(s: String) -> Self {
32-
Key::Str(Cow::Owned(s))
33-
}
19+
/// Insert key for [Array].
20+
#[derive(Debug, Clone, PartialEq, From)]
21+
pub enum InsertKey<'a> {
22+
NextIndex,
23+
Index(u64),
24+
Str(&'a str),
3425
}
3526

3627
/// Wrapper of [crate::sys::zend_array].
@@ -53,14 +44,14 @@ impl Array {
5344
}
5445
}
5546

56-
pub unsafe fn from_ptr<'a>(ptr: *const zend_array) -> &'a Array {
47+
pub unsafe fn from_ptr<'a>(ptr: *const zend_array) -> Option<&'a Array> {
5748
let ptr = ptr as *const Array;
58-
ptr.as_ref().expect("ptr shouldn't be null")
49+
ptr.as_ref()
5950
}
6051

61-
pub unsafe fn from_mut_ptr<'a>(ptr: *mut zend_array) -> &'a mut Array {
52+
pub unsafe fn from_mut_ptr<'a>(ptr: *mut zend_array) -> Option<&'a mut Array> {
6253
let ptr = ptr as *mut Array;
63-
ptr.as_mut().expect("ptr shouldn't be null")
54+
ptr.as_mut()
6455
}
6556

6657
pub fn as_ptr(&self) -> *const zend_array {
@@ -72,15 +63,21 @@ impl Array {
7263
}
7364

7465
// Add or update item by key.
75-
pub fn insert<'a>(&mut self, key: impl Into<Key<'a>>, value: Val) {
66+
pub fn insert<'a>(&mut self, key: impl Into<InsertKey<'a>>, value: Val) {
7667
let key = key.into();
7768
let value = EBox::new(value);
7869
unsafe {
7970
match key {
80-
Key::Index(i) => {
71+
InsertKey::NextIndex => {
72+
phper_zend_hash_next_index_insert(
73+
&mut self.inner,
74+
EBox::into_raw(value).cast(),
75+
);
76+
}
77+
InsertKey::Index(i) => {
8178
phper_zend_hash_index_update(&mut self.inner, i, EBox::into_raw(value).cast());
8279
}
83-
Key::Str(s) => {
80+
InsertKey::Str(s) => {
8481
phper_zend_hash_str_update(
8582
&mut self.inner,
8683
s.as_ptr().cast(),
@@ -118,16 +115,22 @@ impl Array {
118115
unsafe {
119116
match key {
120117
Key::Index(i) => phper_zend_hash_index_exists(&self.inner, i),
121-
Key::Str(s) => phper_zend_hash_str_exists(
122-
&self.inner,
123-
s.as_ref().as_ptr().cast(),
124-
s.as_ref().len(),
125-
),
118+
Key::Str(s) => phper_zend_hash_str_exists(&self.inner, s.as_ptr().cast(), s.len()),
126119
}
127120
}
128121
}
129122

130-
pub fn clone(&self) -> EBox<Self> {
123+
pub fn remove<'a>(&mut self, key: impl Into<Key<'a>>) -> bool {
124+
let key = key.into();
125+
unsafe {
126+
(match key {
127+
Key::Index(i) => zend_hash_index_del(&mut self.inner, i),
128+
Key::Str(s) => zend_hash_str_del(&mut self.inner, s.as_ptr().cast(), s.len()),
129+
}) == ZEND_RESULT_CODE_SUCCESS
130+
}
131+
}
132+
133+
pub fn clone_arr(&self) -> EBox<Self> {
131134
let mut other = Self::new();
132135
unsafe {
133136
zend_hash_copy(other.as_mut_ptr(), self.as_ptr() as *mut _, None);
@@ -146,11 +149,9 @@ impl Array {
146149
impl EAllocatable for Array {
147150
fn free(ptr: *mut Self) {
148151
unsafe {
152+
(*ptr).inner.gc.refcount -= 1;
149153
if (*ptr).inner.gc.refcount == 0 {
150-
zend_hash_destroy(ptr.cast());
151-
_efree(ptr.cast());
152-
} else {
153-
(*ptr).inner.gc.refcount -= 1;
154+
zend_array_destroy(ptr.cast());
154155
}
155156
}
156157
}
@@ -162,6 +163,7 @@ impl Drop for Array {
162163
}
163164
}
164165

166+
/// Iter created by [Array::iter].
165167
pub struct Iter<'a> {
166168
index: isize,
167169
array: &'a Array,
@@ -182,9 +184,9 @@ impl<'a> Iterator for Iter<'a> {
182184
let key = if (*bucket).key.is_null() {
183185
Key::Index((*bucket).h)
184186
} else {
185-
let s = ZendString::from_ptr((*bucket).key);
186-
let s = s.to_string().unwrap();
187-
Key::Str(Cow::Owned(s))
187+
let s = ZendString::from_ptr((*bucket).key).unwrap();
188+
let s = s.as_str().unwrap();
189+
Key::Str(s)
188190
};
189191

190192
let val = &mut (*bucket).val;

phper/src/classes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,12 @@ impl<T: 'static> ClassEntry<T> {
252252
}
253253

254254
pub fn get_name(&self) -> &ZendString {
255-
ZendString::from_ptr(self.inner.name)
255+
unsafe { ZendString::from_ptr(self.inner.name).unwrap() }
256256
}
257257

258258
pub fn has_method(&self, method_name: &str) -> bool {
259259
unsafe {
260-
let function_table = Array::from_ptr(&self.inner.function_table);
260+
let function_table = Array::from_ptr(&self.inner.function_table).unwrap();
261261
function_table.exists(method_name)
262262
}
263263
}

phper/src/functions.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,8 @@ impl ZendFunction {
284284
|| ret_val.get_type().is_undef()
285285
{
286286
Err(CallMethodError::new(
287-
object.get_class().get_name().to_string()?,
288-
self.get_name().to_string()?,
287+
object.get_class().get_name().as_str()?.to_owned(),
288+
self.get_name().as_str()?.to_owned(),
289289
)
290290
.into())
291291
} else {
@@ -324,10 +324,10 @@ unsafe extern "C" fn invoke(execute_data: *mut zend_execute_data, return_value:
324324
if num_args < required_num_args {
325325
let func_name = execute_data.func().get_name();
326326
let result = func_name
327-
.to_string()
327+
.as_str()
328328
.map(|func_name| {
329329
Err::<(), _>(ArgumentCountError::new(
330-
func_name,
330+
func_name.to_owned(),
331331
required_num_args,
332332
num_args,
333333
))

phper/src/objects.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl<T: 'static> Object<T> {
178178
) {
179179
Ok(ret)
180180
} else {
181-
let class_name = self.get_class().get_name().to_string()?;
181+
let class_name = self.get_class().get_name().as_str()?.to_owned();
182182
Err(CallMethodError::new(class_name, method_name.to_owned()).into())
183183
}
184184
}
@@ -211,15 +211,14 @@ impl Object<()> {
211211
impl<T> EAllocatable for Object<T> {
212212
fn free(ptr: *mut Self) {
213213
unsafe {
214+
(*ptr).inner.gc.refcount -= 1;
214215
if (*ptr).inner.gc.refcount == 0 {
215216
let handlers = (*ptr).inner.handlers;
216217
(*handlers).dtor_obj.unwrap()(ptr.cast());
217218
(*handlers).free_obj.unwrap()(ptr.cast());
218219

219220
// zend_objects_store_call_destructors(ptr.cast());
220221
// zend_objects_store_free_object_storage(ptr.cast(), true.into());
221-
} else {
222-
(*ptr).inner.gc.refcount -= 1;
223222
}
224223
}
225224
}

phper/src/strings.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ pub struct ZendString {
1313
}
1414

1515
impl ZendString {
16-
pub fn new(s: &str) -> EBox<Self> {
16+
pub fn new(s: impl AsRef<[u8]>) -> EBox<Self> {
1717
unsafe {
18+
let s = s.as_ref();
1819
let ptr = phper_zend_string_init(s.as_ptr().cast(), s.len(), false.into()).cast();
1920
EBox::from_raw(ptr)
2021
}
@@ -24,11 +25,9 @@ impl ZendString {
2425
EBox::from_raw(ptr as *mut ZendString)
2526
}
2627

27-
pub(crate) fn from_ptr<'a>(ptr: *mut zend_string) -> &'a Self {
28-
unsafe {
29-
let ptr = ptr as *mut Self;
30-
ptr.as_ref().unwrap()
31-
}
28+
pub unsafe fn from_ptr<'a>(ptr: *mut zend_string) -> Option<&'a Self> {
29+
let ptr = ptr as *mut Self;
30+
ptr.as_ref()
3231
}
3332

3433
pub fn as_ptr(&self) -> *const zend_string {
@@ -39,26 +38,33 @@ impl ZendString {
3938
&mut self.inner
4039
}
4140

42-
pub fn to_string(&self) -> Result<String, Utf8Error> {
41+
pub fn as_str(&self) -> Result<&str, Utf8Error> {
42+
str::from_utf8(self.as_ref())
43+
}
44+
}
45+
46+
impl AsRef<[u8]> for ZendString {
47+
fn as_ref(&self) -> &[u8] {
4348
unsafe {
44-
let buf = from_raw_parts(
49+
from_raw_parts(
4550
&self.inner.val as *const c_char as *const u8,
4651
self.inner.len,
47-
);
48-
let string = str::from_utf8(buf)?.to_string();
49-
Ok(string)
52+
)
5053
}
5154
}
5255
}
5356

57+
impl<Rhs: AsRef<[u8]>> PartialEq<Rhs> for ZendString {
58+
fn eq(&self, other: &Rhs) -> bool {
59+
self.as_ref() == other.as_ref()
60+
}
61+
}
62+
5463
impl EAllocatable for ZendString {
5564
fn free(ptr: *mut Self) {
5665
unsafe {
57-
if (*ptr).inner.gc.refcount == 0 {
58-
phper_zend_string_release(ptr.cast());
59-
} else {
60-
(*ptr).inner.gc.refcount -= 1;
61-
}
66+
// Already has `GC_DELREF(s) == 0` detection.
67+
phper_zend_string_release(ptr.cast());
6268
}
6369
}
6470
}

phper/src/values.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
classes::ClassEntry,
77
errors::{CallFunctionError, Throwable, TypeError},
88
functions::ZendFunction,
9-
objects::{Object, StatelessObject},
9+
objects::Object,
1010
strings::ZendString,
1111
sys::*,
1212
types::Type,
@@ -181,8 +181,8 @@ impl Val {
181181
pub fn as_string(&self) -> crate::Result<String> {
182182
if self.get_type().is_string() {
183183
unsafe {
184-
let zs = ZendString::from_ptr(self.inner.value.str);
185-
Ok(zs.to_string()?)
184+
let zs = ZendString::from_ptr(self.inner.value.str).unwrap();
185+
Ok(zs.as_str()?.to_owned())
186186
}
187187
} else {
188188
Err(self.must_be_type_error("string").into())
@@ -192,15 +192,15 @@ impl Val {
192192
pub fn as_string_value(&self) -> Result<String, Utf8Error> {
193193
unsafe {
194194
let s = phper_zval_get_string(&self.inner as *const _ as *mut _);
195-
ZendString::from_raw(s).to_string()
195+
ZendString::from_raw(s).as_str().map(ToOwned::to_owned)
196196
}
197197
}
198198

199199
pub fn as_array(&self) -> crate::Result<&Array> {
200200
if self.get_type().is_array() {
201201
unsafe {
202202
let ptr = self.inner.value.arr;
203-
Ok(Array::from_mut_ptr(ptr))
203+
Ok(Array::from_mut_ptr(ptr).unwrap())
204204
}
205205
} else {
206206
Err(self.must_be_type_error("array").into())
@@ -264,7 +264,7 @@ impl Val {
264264
}
265265

266266
unsafe fn drop_value(&mut self) {
267-
phper_zval_dtor(self.as_mut_ptr());
267+
phper_zval_ptr_dtor_nogc(self.as_mut_ptr());
268268
}
269269
}
270270

0 commit comments

Comments
 (0)