1
1
//! Apis relate to [crate::sys::zend_class_entry].
2
2
3
- use crate :: {
4
- errors:: { ClassNotFoundError , Throwable } ,
5
- functions:: { Argument , FunctionEntity , FunctionEntry , Method } ,
6
- objects:: Object ,
7
- sys:: * ,
8
- utils:: ensure_end_with_zero,
9
- values:: { SetVal , Val } ,
10
- } ;
11
- use once_cell:: sync:: OnceCell ;
12
3
use std:: {
13
4
convert:: Infallible ,
14
5
marker:: PhantomData ,
@@ -17,17 +8,43 @@ use std::{
17
8
ptr:: null_mut,
18
9
sync:: atomic:: { AtomicPtr , Ordering } ,
19
10
} ;
11
+ use std:: any:: Any ;
12
+ use std:: collections:: HashMap ;
13
+ use std:: mem:: { ManuallyDrop , size_of} ;
14
+ use std:: sync:: Arc ;
15
+
16
+ use dashmap:: DashMap ;
17
+ use once_cell:: sync:: OnceCell ;
18
+
19
+ use phper_alloc:: EBox ;
20
+
21
+ use crate :: {
22
+ errors:: { ClassNotFoundError , Throwable } ,
23
+ functions:: { Argument , FunctionEntity , FunctionEntry , Method } ,
24
+ objects:: Object ,
25
+ sys:: * ,
26
+ utils:: ensure_end_with_zero,
27
+ values:: { SetVal , Val } ,
28
+ } ;
29
+ use crate :: objects:: ExtendObject ;
20
30
21
31
pub trait Classifiable {
32
+ fn state_constructor ( & self ) -> Box < StateConstructor < Box < dyn Any > > > ;
22
33
fn class_name ( & self ) -> & str ;
23
34
fn methods ( & mut self ) -> & mut [ FunctionEntity ] ;
24
35
fn properties ( & mut self ) -> & mut [ PropertyEntity ] ;
25
36
fn parent ( & self ) -> Option < & str > ;
26
37
}
27
38
39
+ // TODO Let pointer address as a field of Object isn't safe, will choose another plan later.
40
+ pub ( crate ) const DATA_CONSTRUCTOR_PROPERTY_NAME : & ' static str = "__very_important_do_not_modify_data_constructor__" ;
41
+ pub ( crate ) const DATA_PROPERTY_NAME : & ' static str = "__very_important_do_not_modify_data__" ;
42
+
43
+ pub type StateConstructor < T > = dyn Fn ( ) -> Result < T , Box < dyn Throwable > > + Send + Sync ;
44
+
28
45
pub struct DynamicClass < T : Send + Sync + ' static > {
29
46
class_name : String ,
30
- data_constructor : Box < dyn FnOnce ( & mut Object < T > ) -> Result < T , Box < dyn Throwable > > > ,
47
+ // data_constructor: Box<DataConstructor<T >>,
31
48
pub ( crate ) method_entities : Vec < FunctionEntity > ,
32
49
pub ( crate ) property_entities : Vec < PropertyEntity > ,
33
50
pub ( crate ) parent : Option < String > ,
@@ -36,30 +53,35 @@ pub struct DynamicClass<T: Send + Sync + 'static> {
36
53
37
54
impl DynamicClass < ( ) > {
38
55
pub fn new ( class_name : impl ToString ) -> Self {
39
- Self :: new_with_constructor ( class_name, |_ | Ok :: < _ , Infallible > ( ( ) ) )
56
+ Self :: new_with_constructor ( class_name, || Ok :: < _ , Infallible > ( ( ) ) )
40
57
}
41
58
}
42
59
43
60
impl < T : Default + Send + Sync + ' static > DynamicClass < T > {
44
61
pub fn new_with_default ( class_name : impl ToString ) -> Self {
45
- Self :: new_with_constructor ( class_name, |_ | Ok :: < _ , Infallible > ( Default :: default ( ) ) )
62
+ Self :: new_with_constructor ( class_name, || Ok :: < _ , Infallible > ( Default :: default ( ) ) )
46
63
}
47
64
}
48
65
49
66
impl < T : Send + Sync + ' static > DynamicClass < T > {
50
67
pub fn new_with_constructor < F , E > ( class_name : impl ToString , data_constructor : F ) -> Self
51
68
where
52
- F : FnOnce ( & mut Object < T > ) -> Result < T , E > + ' static ,
69
+ F : Fn ( ) -> Result < T , E > + Send + Sync + ' static ,
53
70
E : Throwable + ' static ,
54
71
{
55
- Self {
72
+ let mut dyn_class = Self {
56
73
class_name : class_name. to_string ( ) ,
57
- data_constructor : Box :: new ( |o | data_constructor ( o ) . map_err ( |e| Box :: new ( e) as _ ) ) ,
74
+ // data_constructor: Box::new(|| data_constructor().map_err(|e| Box::new(e) as _)),
58
75
method_entities : Vec :: new ( ) ,
59
76
property_entities : Vec :: new ( ) ,
60
77
parent : None ,
61
78
_p : Default :: default ( ) ,
62
- }
79
+ } ;
80
+
81
+ // let ptr = &dyn_class.data_constructor as *const _ as usize;
82
+ // dyn_class.add_property(DATA_CONSTRUCTOR_PROPERTY_NAME, ptr.to_string());
83
+
84
+ dyn_class
63
85
}
64
86
65
87
pub fn add_method < F , R > ( & mut self , name : impl ToString , handler : F , arguments : Vec < Argument > )
@@ -86,6 +108,10 @@ impl<T: Send + Sync + 'static> DynamicClass<T> {
86
108
}
87
109
88
110
impl < T : Send + Sync > Classifiable for DynamicClass < T > {
111
+ fn state_constructor ( & self ) -> Box < StateConstructor < Box < dyn Any > > > {
112
+ Box :: new ( || Ok ( Box :: new ( ( ) ) ) )
113
+ }
114
+
89
115
fn class_name ( & self ) -> & str {
90
116
& self . class_name
91
117
}
@@ -147,16 +173,16 @@ fn find_global_class_entry_ptr(name: impl AsRef<str>) -> *mut zend_class_entry {
147
173
pub struct ClassEntity {
148
174
pub ( crate ) name : String ,
149
175
pub ( crate ) entry : AtomicPtr < ClassEntry > ,
150
- pub ( crate ) class : Box < dyn Classifiable > ,
176
+ pub ( crate ) classifiable : Box < dyn Classifiable > ,
151
177
pub ( crate ) function_entries : OnceCell < AtomicPtr < FunctionEntry > > ,
152
178
}
153
179
154
180
impl ClassEntity {
155
- pub ( crate ) unsafe fn new ( class : impl Classifiable + ' static ) -> Self {
181
+ pub ( crate ) unsafe fn new ( classifiable : impl Classifiable + ' static ) -> Self {
156
182
Self {
157
- name : class . class_name ( ) . to_string ( ) ,
183
+ name : classifiable . class_name ( ) . to_string ( ) ,
158
184
entry : AtomicPtr :: new ( null_mut ( ) ) ,
159
- class : Box :: new ( class ) ,
185
+ classifiable : Box :: new ( classifiable ) ,
160
186
function_entries : Default :: default ( ) ,
161
187
}
162
188
}
@@ -169,17 +195,22 @@ impl ClassEntity {
169
195
) ;
170
196
171
197
let parent = self
172
- . class
198
+ . classifiable
173
199
. parent ( )
174
200
. map ( |s| ClassEntry :: from_globals ( s) . unwrap ( ) ) ;
175
201
176
- let ptr = match parent {
202
+ let class : * mut ClassEntry = match parent {
177
203
Some ( parent) => {
178
204
zend_register_internal_class_ex ( & mut class_ce, parent. as_ptr ( ) as * mut _ ) . cast ( )
179
205
}
180
206
None => zend_register_internal_class ( & mut class_ce) . cast ( ) ,
181
207
} ;
182
- self . entry . store ( ptr, Ordering :: SeqCst ) ;
208
+ self . entry . store ( class, Ordering :: SeqCst ) ;
209
+
210
+ ( * class) . inner . __bindgen_anon_2 . create_object = Some ( create_object) ;
211
+
212
+ // let classifiable = self.classifiable.clone();
213
+ // get_class_constructor_map().insert(class as usize, Box::new(move || classifiable.state_constructor()));
183
214
184
215
// let methods = self.class.methods();
185
216
// for method in methods {
@@ -193,7 +224,7 @@ impl ClassEntity {
193
224
}
194
225
195
226
pub ( crate ) unsafe fn declare_properties ( & mut self ) {
196
- let properties = self . class . properties ( ) ;
227
+ let properties = self . classifiable . properties ( ) ;
197
228
for property in properties {
198
229
let value = ensure_end_with_zero ( property. value . clone ( ) ) ;
199
230
zend_declare_property_string (
@@ -207,18 +238,32 @@ impl ClassEntity {
207
238
}
208
239
209
240
unsafe fn function_entries ( & mut self ) -> & AtomicPtr < FunctionEntry > {
210
- let methods = & * self . class . methods ( ) ;
241
+ let last_entry = self . take_classifiable_into_function_entry ( ) ;
242
+ let methods = & * self . classifiable . methods ( ) ;
211
243
212
244
self . function_entries . get_or_init ( || {
213
245
let mut methods = methods
214
246
. iter ( )
215
247
. map ( |method| method. entry ( ) )
216
248
. collect :: < Vec < _ > > ( ) ;
249
+
217
250
methods. push ( zeroed :: < zend_function_entry > ( ) ) ;
251
+
252
+ // Store the classifiable pointer to zend_class_entry
253
+ methods. push ( last_entry) ;
254
+
218
255
let entry = Box :: into_raw ( methods. into_boxed_slice ( ) ) . cast ( ) ;
219
256
AtomicPtr :: new ( entry)
220
257
} )
221
258
}
259
+
260
+ unsafe fn take_classifiable_into_function_entry ( & self ) -> zend_function_entry {
261
+ let mut entry = zeroed :: < zend_function_entry > ( ) ;
262
+ let ptr = & mut entry as * mut _ as * mut ManuallyDrop < Box < StateConstructor < Box < Any > > > > ;
263
+ let state_constructor = ManuallyDrop :: new ( self . classifiable . state_constructor ( ) ) ;
264
+ ptr. write ( state_constructor) ;
265
+ entry
266
+ }
222
267
}
223
268
224
269
pub struct PropertyEntity {
@@ -243,3 +288,46 @@ pub enum Visibility {
243
288
Protected = ZEND_ACC_PROTECTED ,
244
289
Private = ZEND_ACC_PRIVATE ,
245
290
}
291
+
292
+ fn get_object_handlers ( ) -> & ' static zend_object_handlers {
293
+ static OBJECT_HANDLERS : OnceCell < zend_object_handlers > = OnceCell :: new ( ) ;
294
+ OBJECT_HANDLERS . get_or_init ( || unsafe {
295
+ let mut handlers = std_object_handlers;
296
+ handlers. offset = ExtendObject :: offset ( ) as c_int ;
297
+ handlers. free_obj = Some ( destroy_object) ;
298
+ handlers
299
+ } )
300
+ }
301
+
302
+ unsafe extern "C" fn create_object ( ce : * mut zend_class_entry ) -> * mut zend_object {
303
+ // Alloc more memory size to store state data.
304
+ let extend_object: * mut ExtendObject = phper_zend_object_alloc ( size_of :: < ExtendObject > ( ) , ce) . cast ( ) ;
305
+
306
+ // Common initialize process.
307
+ let object = & mut ( * extend_object) . object ;
308
+ zend_object_std_init ( object, ce) ;
309
+ object_properties_init ( object, ce) ;
310
+ rebuild_object_properties ( object) ;
311
+ object. handlers = get_object_handlers ( ) ;
312
+
313
+ // Get state constructor.
314
+ let mut func_ptr = ( * ce) . info . internal . builtin_functions ;
315
+ while !( * func_ptr) . fname . is_null ( ) {
316
+ func_ptr = func_ptr. offset ( 1 ) ;
317
+ }
318
+ func_ptr = func_ptr. offset ( 1 ) ;
319
+ let state_constructor = func_ptr as * const ManuallyDrop < Box < StateConstructor < Box < Any > > > > ;
320
+ let state_constructor = state_constructor. read ( ) ;
321
+
322
+ // Call the state constructor.
323
+ // TODO Throw an exception rather than unwrap.
324
+ let data: Box < dyn Any > = state_constructor ( ) . unwrap ( ) ;
325
+ ( * extend_object) . state = ManuallyDrop :: new ( data) ;
326
+
327
+ object
328
+ }
329
+
330
+ unsafe extern "C" fn destroy_object ( object : * mut zend_object ) {
331
+ // Original destroy call.
332
+ zend_object_std_dtor ( object) ;
333
+ }
0 commit comments