@@ -28,26 +28,14 @@ use std::{
2828 ffi:: { CString , c_char, c_void} ,
2929 fmt:: Debug ,
3030 marker:: PhantomData ,
31- mem:: { ManuallyDrop , replace, size_of, zeroed} ,
31+ mem:: { ManuallyDrop , replace, size_of, transmute , zeroed} ,
3232 os:: raw:: c_int,
3333 ptr,
3434 ptr:: null_mut,
3535 rc:: Rc ,
3636 slice,
3737} ;
3838
39- /// Predefined interface `Iterator`.
40- #[ inline]
41- pub fn iterator_class < ' a > ( ) -> & ' a ClassEntry {
42- unsafe { ClassEntry :: from_ptr ( zend_ce_iterator) }
43- }
44-
45- /// Predefined interface `ArrayAccess`.
46- #[ inline]
47- pub fn array_access_class < ' a > ( ) -> & ' a ClassEntry {
48- unsafe { ClassEntry :: from_ptr ( zend_ce_arrayaccess) }
49- }
50-
5139/// Wrapper of [zend_class_entry].
5240#[ derive( Clone ) ]
5341#[ repr( transparent) ]
@@ -287,13 +275,26 @@ fn find_global_class_entry_ptr(name: impl AsRef<str>) -> *mut zend_class_entry {
287275/// ```
288276pub struct StateClass < T > {
289277 inner : Rc < RefCell < * mut zend_class_entry > > ,
278+ name : Option < String > ,
290279 _p : PhantomData < T > ,
291280}
292281
282+ impl StateClass < ( ) > {
283+ /// Create from name, which will be looked up from globals.
284+ pub fn from_name ( name : impl Into < String > ) -> Self {
285+ Self {
286+ inner : Rc :: new ( RefCell :: new ( null_mut ( ) ) ) ,
287+ name : Some ( name. into ( ) ) ,
288+ _p : PhantomData ,
289+ }
290+ }
291+ }
292+
293293impl < T > StateClass < T > {
294294 fn null ( ) -> Self {
295295 Self {
296296 inner : Rc :: new ( RefCell :: new ( null_mut ( ) ) ) ,
297+ name : None ,
297298 _p : PhantomData ,
298299 }
299300 }
@@ -304,7 +305,11 @@ impl<T> StateClass<T> {
304305
305306 /// Converts to class entry.
306307 pub fn as_class_entry ( & self ) -> & ClassEntry {
307- unsafe { ClassEntry :: from_mut_ptr ( * self . inner . borrow ( ) ) }
308+ if let Some ( name) = & self . name {
309+ ClassEntry :: from_globals ( name) . unwrap ( )
310+ } else {
311+ unsafe { ClassEntry :: from_mut_ptr ( * self . inner . borrow ( ) ) }
312+ }
308313 }
309314
310315 /// Create the object from class and call `__construct` with arguments.
@@ -333,6 +338,7 @@ impl<T> Clone for StateClass<T> {
333338 fn clone ( & self ) -> Self {
334339 Self {
335340 inner : self . inner . clone ( ) ,
341+ name : self . name . clone ( ) ,
336342 _p : self . _p ,
337343 }
338344 }
@@ -427,7 +433,7 @@ pub struct ClassEntity<T: 'static> {
427433 state_constructor : Rc < StateConstructor > ,
428434 method_entities : Vec < MethodEntity > ,
429435 property_entities : Vec < PropertyEntity > ,
430- parent : Option < Box < dyn Fn ( ) -> & ' static ClassEntry > > ,
436+ parent : Option < StateClass < ( ) > > ,
431437 interfaces : Vec < Interface > ,
432438 constants : Vec < ConstantEntity > ,
433439 bind_class : StateClass < T > ,
@@ -550,19 +556,40 @@ impl<T: 'static> ClassEntity<T> {
550556 /// Register class to `extends` the parent class.
551557 ///
552558 /// *Because in the `MINIT` phase, the class starts to register, so the*
553- /// *closure is used to return the `ClassEntry` to delay the acquisition of*
559+ /// *`ClassEntry` is looked up by name to delay the acquisition of*
554560 /// *the class.*
555561 ///
556562 /// # Examples
557563 ///
558564 /// ```no_run
559- /// use phper::classes::{ClassEntity, ClassEntry};
565+ /// use phper::{
566+ /// classes::{ClassEntity, ClassEntry, StateClass},
567+ /// modules::Module,
568+ /// php_get_module,
569+ /// };
560570 ///
561- /// let mut class = ClassEntity::new("MyException");
562- /// class.extends(|| ClassEntry::from_globals("Exception").unwrap());
571+ /// #[php_get_module]
572+ /// pub fn get_module() -> Module {
573+ /// let mut module = Module::new(
574+ /// env!("CARGO_CRATE_NAME"),
575+ /// env!("CARGO_PKG_VERSION"),
576+ /// env!("CARGO_PKG_AUTHORS"),
577+ /// );
578+ ///
579+ /// let foo = module.add_class(ClassEntity::new("Foo"));
580+ /// let mut bar = ClassEntity::new("Bar");
581+ /// bar.extends(foo);
582+ /// module.add_class(bar);
583+ ///
584+ /// let mut ex = ClassEntity::new("MyException");
585+ /// ex.extends(StateClass::from_name("Exception"));
586+ /// module.add_class(ex);
587+ ///
588+ /// module
589+ /// }
563590 /// ```
564- pub fn extends ( & mut self , parent : impl Fn ( ) -> & ' static ClassEntry + ' static ) {
565- self . parent = Some ( Box :: new ( parent) ) ;
591+ pub fn extends < S : ' static > ( & mut self , parent : StateClass < S > ) {
592+ self . parent = Some ( unsafe { transmute :: < StateClass < S > , StateClass < ( ) > > ( parent) } ) ;
566593 }
567594
568595 /// Register class to `implements` the interface, due to the class can
@@ -634,7 +661,7 @@ impl<T: 'static> ClassEntity<T> {
634661 let parent: * mut zend_class_entry = self
635662 . parent
636663 . as_ref ( )
637- . map ( |parent| parent ( ) )
664+ . map ( |parent| parent. as_class_entry ( ) )
638665 . map ( |entry| entry. as_ptr ( ) as * mut _ )
639666 . unwrap_or ( null_mut ( ) ) ;
640667
@@ -800,20 +827,24 @@ impl InterfaceEntity {
800827 /// Register interface to `extends` the interfaces, due to the interface can
801828 /// extends multi interface, so this method can be called multi time.
802829 ///
803- /// *Because in the `MINIT` phase, the class starts to register, so the *
830+ /// *Because in the `MINIT` phase, the class starts to register, a *
804831 /// *closure is used to return the `ClassEntry` to delay the acquisition of*
805832 /// *the class.*
806833 ///
807834 /// # Examples
808835 ///
809836 /// ```no_run
810- /// use phper::classes::{ClassEntry , InterfaceEntity};
837+ /// use phper::classes::{Interface , InterfaceEntity};
811838 ///
812839 /// let mut interface = InterfaceEntity::new("MyInterface");
813- /// interface.extends(|| ClassEntry::from_globals ("Stringable").unwrap( ));
840+ /// interface.extends(Interface::from_name ("Stringable"));
814841 /// ```
815- pub fn extends ( & mut self , interface : impl Fn ( ) -> & ' static ClassEntry + ' static ) {
816- self . extends . push ( Box :: new ( interface) ) ;
842+ pub fn extends ( & mut self , interface : Interface ) {
843+ self . extends . push ( Box :: new ( move || {
844+ let entry: & ' static ClassEntry =
845+ unsafe { std:: mem:: transmute ( interface. as_class_entry ( ) ) } ;
846+ entry
847+ } ) ) ;
817848 }
818849
819850 #[ allow( clippy:: useless_conversion) ]
0 commit comments