Skip to content

Commit 4dd852f

Browse files
authored
Add into state method for StateObject, and refactor StateObj. (#120)
1 parent 3405afd commit 4dd852f

File tree

10 files changed

+178
-131
lines changed

10 files changed

+178
-131
lines changed

examples/http-client/src/client.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ pub fn make_client_builder_class() -> ClassEntity<ClientBuilder> {
5252
class.add_method("build", Visibility::Public, |this, _arguments| {
5353
let state = take(this.as_mut_state());
5454
let client = ClientBuilder::build(state).map_err(HttpClientError::Reqwest)?;
55-
let mut object = ClassEntry::from_globals(HTTP_CLIENT_CLASS_NAME)?.init_object()?;
55+
let class = ClassEntry::from_globals(HTTP_CLIENT_CLASS_NAME)?;
56+
let mut object = class.init_object()?;
5657
unsafe {
57-
*object.as_mut_state() = Some(client);
58+
*object.as_mut_state_obj().as_mut_state() = Some(client);
5859
}
5960
Ok::<_, phper::Error>(object)
6061
});
@@ -77,7 +78,7 @@ pub fn make_client_class() -> ClassEntity<Option<Client>> {
7778
let request_builder = client.get(url);
7879
let mut object = ClassEntry::from_globals(REQUEST_BUILDER_CLASS_NAME)?.init_object()?;
7980
unsafe {
80-
*object.as_mut_state() = Some(request_builder);
81+
*object.as_mut_state_obj().as_mut_state() = Some(request_builder);
8182
}
8283
Ok::<_, phper::Error>(object)
8384
})
@@ -90,7 +91,7 @@ pub fn make_client_class() -> ClassEntity<Option<Client>> {
9091
let request_builder = client.post(url);
9192
let mut object = ClassEntry::from_globals(REQUEST_BUILDER_CLASS_NAME)?.init_object()?;
9293
unsafe {
93-
*object.as_mut_state() = Some(request_builder);
94+
*object.as_mut_state_obj().as_mut_state() = Some(request_builder);
9495
}
9596
Ok::<_, phper::Error>(object)
9697
})

examples/http-client/src/request.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn make_request_builder_class() -> ClassEntity<Option<RequestBuilder>> {
3434
.map_err(ThrowObject::from_throwable)?
3535
.new_object([])?;
3636
unsafe {
37-
*object.as_mut_state() = Some(response);
37+
*object.as_mut_state_obj().as_mut_state() = Some(response);
3838
}
3939
Ok::<_, phper::Error>(object)
4040
});

examples/http-server/src/request.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::convert::Infallible;
1717

1818
pub const HTTP_REQUEST_CLASS_NAME: &str = "HttpServer\\HttpRequest";
1919

20-
pub static HTTP_REQUEST_CLASS: StateClass<()> = StateClass::new();
20+
pub static HTTP_REQUEST_CLASS: StateClass<()> = StateClass::null();
2121

2222
/// Register the class `HttpServer\HttpRequest` by `ClassEntity`.
2323
pub fn make_request_class() -> ClassEntity<()> {

examples/http-server/src/response.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use phper::{
2121

2222
pub const HTTP_RESPONSE_CLASS_NAME: &str = "HttpServer\\HttpResponse";
2323

24-
pub static HTTP_RESPONSE_CLASS: StateClass<Response<Body>> = StateClass::new();
24+
pub static HTTP_RESPONSE_CLASS: StateClass<Response<Body>> = StateClass::null();
2525

2626
/// Register the class `HttpServer\HttpResponse` by `ClassEntity`, with the
2727
/// inner state `Response<Body>`.

examples/http-server/src/server.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use phper::{
2222
functions::Argument,
2323
values::ZVal,
2424
};
25-
use std::{cell::RefCell, collections::HashMap, mem::take, net::SocketAddr};
25+
use std::{cell::RefCell, collections::HashMap, net::SocketAddr};
2626
use tokio::runtime::{self};
2727

2828
const HTTP_SERVER_CLASS_NAME: &str = "HttpServer\\HttpServer";
@@ -128,8 +128,7 @@ pub fn make_server_class() -> ClassEntity<()> {
128128
handler.call([request_val, response_val])?;
129129

130130
// Get the inner state.
131-
let response =
132-
take(unsafe { response.as_mut_state::<Response<Body>>() });
131+
let response = response.into_state().unwrap();
133132

134133
Ok::<Response<Body>, phper::Error>(response)
135134
})

phper-doc/doc/_02_quick_start/_02_write_a_simple_http_client/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ Now let's begin to finish the logic.
236236
let client = ClientBuilder::build(state).map_err(HttpClientError::Reqwest)?;
237237
let mut object = ClassEntry::from_globals(HTTP_CLIENT_CLASS_NAME)?.init_object()?;
238238
unsafe {
239-
*object.as_mut_state() = Some(client);
239+
*object.as_mut_state_obj().as_mut_state() = Some(client);
240240
}
241241
Ok::<_, phper::Error>(object)
242242
});

phper-doc/doc/_05_internal_types/index.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ PHPER follows this design, there are the following types:
1818
- [ZArr](phper::arrays::ZArr) / [ZArray](phper::arrays::ZArray)
1919
- [ZObj](phper::objects::ZObj) / [ZObject](phper::objects::ZObject)
2020

21+
> It seems that there is no need to separate into two types, but `ZStr`,
22+
> `ZArr`, and `ZObj` are all transparent types, so the fields of the struct
23+
> cannot be changed. Separating an ownership struct `ZString`, `ZArray`,
24+
> and `ZObject`, and then we can change fields of the struct in the future.
25+
2126
## Mapping relationship
2227

2328
Here is the mapping relationship of Rust type and base PHP type.

phper-sys/php_wrapper.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ void phper_zend_object_release(zend_object *obj) {
348348
zend_object_release(obj);
349349
}
350350

351+
uint32_t phper_zend_object_gc_refcount(const zend_object *obj) {
352+
return GC_REFCOUNT(obj);
353+
}
354+
351355
// ==================================================
352356
// class apis:
353357
// ==================================================

phper/src/classes.rs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,22 @@ use crate::{
1414
arrays::ZArr,
1515
errors::{ClassNotFoundError, InitializeObjectError, Throwable},
1616
functions::{Function, FunctionEntry, Method, MethodEntity},
17-
objects::{CStateObject, StateObj, StateObject, ZObj, ZObject},
17+
objects::{StateObj, StateObject, ZObject},
1818
strings::ZStr,
1919
sys::*,
2020
types::Scalar,
2121
utils::ensure_end_with_zero,
2222
values::ZVal,
2323
};
2424
use once_cell::sync::OnceCell;
25-
use phper_alloc::ToRefOwned;
2625
use std::{
2726
any::Any,
2827
borrow::ToOwned,
2928
convert::TryInto,
3029
ffi::{c_void, CString},
3130
fmt::Debug,
3231
marker::PhantomData,
33-
mem::{size_of, zeroed},
32+
mem::{size_of, zeroed, ManuallyDrop},
3433
os::raw::c_int,
3534
ptr::null_mut,
3635
rc::Rc,
@@ -156,8 +155,11 @@ impl ClassEntry {
156155
if !phper_object_init_ex(val.as_mut_ptr(), ptr) {
157156
Err(InitializeObjectError::new(self.get_name().to_str()?.to_owned()).into())
158157
} else {
158+
// Can't drop val here! Otherwise the object will be dropped too (wasting me a
159+
// day of debugging time here).
160+
let mut val = ManuallyDrop::new(val);
159161
let ptr = phper_z_obj_p(val.as_mut_ptr());
160-
Ok(ZObj::from_mut_ptr(ptr).to_ref_owned())
162+
Ok(ZObject::from_raw(ptr))
161163
}
162164
}
163165
}
@@ -218,7 +220,7 @@ fn find_global_class_entry_ptr(name: impl AsRef<str>) -> *mut zend_class_entry {
218220
/// ```rust
219221
/// use phper::classes::{ClassEntity, StateClass};
220222
///
221-
/// pub static FOO_CLASS: StateClass<FooState> = StateClass::new();
223+
/// pub static FOO_CLASS: StateClass<FooState> = StateClass::null();
222224
///
223225
/// #[derive(Default)]
224226
/// pub struct FooState;
@@ -238,7 +240,7 @@ pub struct StateClass<T> {
238240
impl<T> StateClass<T> {
239241
/// Create empty [StateClass], with null
240242
/// [zend_class_entry](crate::sys::zend_class_entry).
241-
pub const fn new() -> Self {
243+
pub const fn null() -> Self {
242244
Self {
243245
inner: AtomicPtr::new(null_mut()),
244246
_p: PhantomData,
@@ -263,18 +265,22 @@ impl<T> StateClass<T> {
263265
) -> crate::Result<StateObject<T>> {
264266
self.as_class_entry()
265267
.new_object(arguments)
266-
.map(StateObject::new)
268+
.map(ZObject::into_raw)
269+
.map(StateObject::<T>::from_raw_object)
267270
}
268271

269272
/// Create the object from class, without calling `__construct`.
270273
///
271274
/// **Be careful when `__construct` is necessary.**
272275
pub fn init_object(&'static self) -> crate::Result<StateObject<T>> {
273-
self.as_class_entry().init_object().map(StateObject::new)
276+
self.as_class_entry()
277+
.init_object()
278+
.map(ZObject::into_raw)
279+
.map(StateObject::<T>::from_raw_object)
274280
}
275281
}
276282

277-
pub(crate) type StateConstructor = dyn Fn() -> Box<dyn Any>;
283+
pub(crate) type StateConstructor = dyn Fn() -> *mut dyn Any;
278284

279285
/// Builder for registering class.
280286
///
@@ -316,7 +322,11 @@ impl<T: 'static> ClassEntity<T> {
316322
) -> Self {
317323
Self {
318324
class_name: ensure_end_with_zero(class_name),
319-
state_constructor: Rc::new(move || Box::new(state_constructor())),
325+
state_constructor: Rc::new(move || {
326+
let state = state_constructor();
327+
let boxed = Box::new(state) as Box<dyn Any>;
328+
Box::into_raw(boxed)
329+
}),
320330
method_entities: Vec::new(),
321331
property_entities: Vec::new(),
322332
parent: None,
@@ -571,7 +581,7 @@ fn get_object_handlers() -> &'static zend_object_handlers {
571581
static HANDLERS: OnceCell<zend_object_handlers> = OnceCell::new();
572582
HANDLERS.get_or_init(|| unsafe {
573583
let mut handlers = std_object_handlers;
574-
handlers.offset = CStateObject::offset() as c_int;
584+
handlers.offset = StateObj::<()>::offset() as c_int;
575585
handlers.free_obj = Some(free_object);
576586
handlers
577587
})
@@ -580,15 +590,15 @@ fn get_object_handlers() -> &'static zend_object_handlers {
580590
#[allow(clippy::useless_conversion)]
581591
unsafe extern "C" fn create_object(ce: *mut zend_class_entry) -> *mut zend_object {
582592
// Alloc more memory size to store state data.
583-
let state_object: *mut CStateObject =
584-
phper_zend_object_alloc(size_of::<CStateObject>().try_into().unwrap(), ce).cast();
593+
let state_object = phper_zend_object_alloc(size_of::<StateObj<()>>().try_into().unwrap(), ce);
594+
let state_object = StateObj::<()>::from_mut_ptr(state_object);
585595

586596
// Common initialize process.
587-
let object = CStateObject::as_mut_object(state_object);
597+
let object = state_object.as_mut_object().as_mut_ptr();
588598
zend_object_std_init(object, ce);
589599
object_properties_init(object, ce);
590600
rebuild_object_properties(object);
591-
object.handlers = get_object_handlers();
601+
(*object).handlers = get_object_handlers();
592602

593603
// Get state constructor.
594604
let mut func_ptr = (*ce).info.internal.builtin_functions;
@@ -599,17 +609,18 @@ unsafe extern "C" fn create_object(ce: *mut zend_class_entry) -> *mut zend_objec
599609
let state_constructor = func_ptr as *mut *const StateConstructor;
600610
let state_constructor = state_constructor.read();
601611

602-
// Call the state constructor.
603-
let data: Box<dyn Any> = (state_constructor.as_ref().unwrap())();
604-
*CStateObject::as_mut_state(state_object) = Box::into_raw(data);
612+
// Call the state constructor and store the state.
613+
let data = (state_constructor.as_ref().unwrap())();
614+
*state_object.as_mut_any_state() = data;
605615

606616
object
607617
}
608618

609619
unsafe extern "C" fn free_object(object: *mut zend_object) {
620+
let state_object = StateObj::<()>::from_mut_object_ptr(object);
621+
610622
// Drop the state.
611-
let state_object = CStateObject::fetch_ptr(object);
612-
CStateObject::drop_state(state_object);
623+
state_object.drop_state();
613624

614625
// Original destroy call.
615626
zend_object_std_dtor(object);

0 commit comments

Comments
 (0)