Skip to content

Commit db64f74

Browse files
committed
Use repalce to resolve the problem about taking filed ownership of mut ref PropertyEntity.
1 parent b4dcaa8 commit db64f74

File tree

9 files changed

+79
-35
lines changed

9 files changed

+79
-35
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
env:
1010
RUST_LOG: debug
1111
CARGO_TERM_COLOR: always
12-
RUST_BACKTRACE: full
12+
RUST_BACKTRACE: "1"
1313
RUSTFLAGS: "-D warnings"
1414

1515
jobs:

examples/hello/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub fn get_module() -> Module {
6363

6464
// register classes
6565
let mut foo_class = DynamicClass::new("FooClass");
66-
foo_class.add_property("foo", "100".to_string());
66+
foo_class.add_property("foo", Visibility::Public, "100".to_string());
6767
foo_class.add_method(
6868
"getFoo",
6969
Visibility::Public,

phper-sys/php_wrapper.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,6 @@ void phper_zval_obj(zval *z, zend_object *o) {
9494
ZVAL_OBJ(z, o);
9595
}
9696

97-
void phper_zval_obj_copy(zval *z, zend_object *o) {
98-
ZVAL_OBJ_COPY(z, o);
99-
}
100-
10197
#if PHP_VERSION_ID < 80000
10298
static zend_string *phper_zend_string_concat3(
10399
const char *str1, size_t str1_len,

phper-sys/php_wrapper.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ void phper_array_init(zval *arg);
3939
void *phper_zend_hash_str_find_ptr(const HashTable *ht, const char *str, size_t len);
4040

4141
void phper_zval_obj(zval *z, zend_object *o);
42-
void phper_zval_obj_copy(zval *z, zend_object *o);
4342

4443
zend_string *phper_get_function_or_method_name(const zend_function *func);
4544

phper/src/classes.rs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@ use crate::{
66
functions::{Argument, Function, FunctionEntity, FunctionEntry, Method},
77
objects::{ExtendObject, Object},
88
sys::*,
9-
utils::ensure_end_with_zero,
109
values::{SetVal, Val},
1110
};
1211
use dashmap::DashMap;
1312
use once_cell::sync::OnceCell;
1413
use std::{
1514
any::{Any, TypeId},
1615
marker::PhantomData,
17-
mem::{size_of, zeroed, ManuallyDrop},
16+
mem::{replace, size_of, zeroed, ManuallyDrop},
1817
os::raw::c_int,
1918
ptr::null_mut,
2019
sync::{
@@ -119,9 +118,14 @@ impl<T: Send + 'static> DynamicClass<T> {
119118
));
120119
}
121120

122-
pub fn add_property(&mut self, name: impl ToString, value: String) {
121+
pub fn add_property(
122+
&mut self,
123+
name: impl ToString,
124+
vis: Visibility,
125+
value: impl SetVal + Clone,
126+
) {
123127
self.property_entities
124-
.push(PropertyEntity::new(name, value));
128+
.push(PropertyEntity::new(name, vis, value));
125129
}
126130

127131
pub fn extends(&mut self, name: impl ToString) {
@@ -271,31 +275,18 @@ impl ClassEntity {
271275
*phper_get_create_object(class.cast()) = Some(create_object);
272276

273277
get_registered_class_type_map().insert(class as usize, self.classifiable.state_type_id());
274-
275-
// let classifiable = self.classifiable.clone();
276-
// get_class_constructor_map().insert(class as usize, Box::new(move || classifiable.state_constructor()));
277-
278-
// let methods = self.class.methods();
279-
// for method in methods {
280-
// match &method.handler {
281-
// Callable::Method(_, class) => {
282-
// class.store(ptr, Ordering::SeqCst);
283-
// }
284-
// _ => unreachable!(),
285-
// }
286-
// }
287278
}
288279

289280
pub(crate) unsafe fn declare_properties(&mut self) {
290281
let properties = self.classifiable.properties();
291282
for property in properties {
292-
let value = ensure_end_with_zero(property.value.clone());
283+
let val = replace(&mut property.value, None).unwrap();
293284
zend_declare_property_string(
294285
self.entry.load(Ordering::SeqCst).cast(),
295286
property.name.as_ptr().cast(),
296287
property.name.len(),
297-
value.as_ptr().cast(),
298-
Visibility::Public as c_int,
288+
EBox::into_raw(val).cast(),
289+
property.visibility as c_int,
299290
);
300291
}
301292
}
@@ -331,15 +322,16 @@ impl ClassEntity {
331322

332323
pub struct PropertyEntity {
333324
name: String,
334-
// TODO to be a SetVal
335-
value: String,
325+
visibility: Visibility,
326+
value: Option<EBox<Val>>,
336327
}
337328

338329
impl PropertyEntity {
339-
pub fn new(name: impl ToString, value: String) -> Self {
330+
pub fn new(name: impl ToString, visibility: Visibility, value: impl SetVal) -> Self {
340331
Self {
341332
name: name.to_string(),
342-
value,
333+
visibility,
334+
value: Some(EBox::new(Val::new(value))),
343335
}
344336
}
345337
}

phper/src/functions.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//! Apis relate to [crate::sys::zend_function_entry].
2+
//!
3+
//! TODO Add php function call.
24
35
use std::{mem::zeroed, os::raw::c_char};
46

tests/integration/src/classes.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,44 @@
1-
use phper::modules::Module;
1+
use phper::{
2+
classes::{DynamicClass, Visibility},
3+
functions::Argument,
4+
modules::Module,
5+
values::Val,
6+
};
27

38
pub fn integrate(module: &mut Module) {
49
integrate_a(module);
510
}
611

7-
// TODO Write class tests.
8-
fn integrate_a(_module: &mut Module) {
9-
// let class = DynamicClass::new_with_constructor("IntegrationTest\\A", ||);
12+
fn integrate_a(module: &mut Module) {
13+
let mut class = DynamicClass::new("IntegrationTest\\A");
14+
15+
class.add_property("name", Visibility::Private, "default");
16+
class.add_property("number", Visibility::Private, 100);
17+
18+
class.add_method(
19+
"__construct",
20+
Visibility::Public,
21+
|this, arguments| {
22+
let name = arguments[0].as_string()?;
23+
let number = arguments[1].as_long()?;
24+
this.set_property("name", Val::new(name));
25+
this.set_property("number", Val::new(number));
26+
Ok::<_, phper::Error>(())
27+
},
28+
vec![Argument::by_val("name"), Argument::by_val("number")],
29+
);
30+
31+
class.add_method(
32+
"speak",
33+
Visibility::Public,
34+
|this, _arguments| {
35+
let name = this.get_property("name").as_string()?;
36+
let number = this.get_property("number").as_long()?;
37+
38+
Ok::<_, phper::Error>(format!("name: {}, number: {}", name, number))
39+
},
40+
vec![],
41+
);
42+
43+
module.add_class(class);
1044
}

tests/integration/tests/php/_common.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2]));
1010
}
1111

12+
function assert_true($value) {
13+
assert_eq($value, true);
14+
}
15+
16+
function assert_false($value) {
17+
assert_eq($value, false);
18+
}
19+
1220
function assert_eq($left, $right) {
1321
if ($left !== $right) {
1422
throw new AssertionError(sprintf("left != right,\n left: %s,\n right: %s", var_export($left, true), var_export($right, true)));
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
require_once __DIR__ . '/_common.php';
4+
5+
assert_throw(function () { new \IntegrationTest\A(); }, "ArgumentCountError", 0, "IntegrationTest\\A::__construct(): expects at least 2 parameter(s), 0 given");
6+
7+
$a = new \IntegrationTest\A("foo", 99);
8+
assert_eq($a->speak(), "name: foo, number: 99");
9+
10+
$reflection_class = new ReflectionClass(\IntegrationTest\A::class);
11+
12+
$property_name = $reflection_class->getProperty("name");
13+
assert_true($property_name->isPrivate());

0 commit comments

Comments
 (0)