1313
1414use crate :: {
1515 classes:: {
16- ClassEntry , ConstantEntity , InnerClassEntry , Interface , RawVisibility , StateCloner ,
17- StateConstructor , Visibility , add_class_constant, create_object,
16+ ClassEntry , ConstantEntity , InnerClassEntry , Interface , StateConstructor , Visibility ,
17+ add_class_constant, create_object,
1818 } ,
1919 errors:: Throwable ,
20- functions:: { Function , FunctionEntry , HandlerMap , Method , MethodEntity } ,
21- objects:: { AnyState , StateObj , ZObj } ,
20+ functions:: { FunctionEntry , HandlerMap , Method , MethodEntity } ,
21+ objects:: StateObj ,
2222 sys:: * ,
2323 types:: Scalar ,
2424 utils:: ensure_end_with_zero,
@@ -28,11 +28,9 @@ use sealed::sealed;
2828use std:: {
2929 any:: Any ,
3030 cell:: RefCell ,
31- ffi:: { CStr , CString , c_char, c_void} ,
32- fmt:: Debug ,
31+ ffi:: { CStr , CString } ,
3332 marker:: PhantomData ,
34- mem:: { ManuallyDrop , size_of, zeroed} ,
35- ops:: { Deref , DerefMut } ,
33+ mem:: zeroed,
3634 ptr:: { null, null_mut} ,
3735 rc:: Rc ,
3836} ;
@@ -82,6 +80,98 @@ struct EnumCase {
8280 value : Scalar ,
8381}
8482
83+ /// Reference to a specific enum case
84+ pub struct StateEnumCase < T > {
85+ enum_name : CString ,
86+ case_name : CString ,
87+ bound_enum : StateEnum < T > ,
88+ _p : PhantomData < T > ,
89+ }
90+
91+ impl < T > StateEnumCase < T > {
92+ fn new ( enum_name : CString , case_name : CString , bound_enum : StateEnum < T > ) -> Self {
93+ Self {
94+ enum_name,
95+ case_name,
96+ bound_enum,
97+ _p : PhantomData ,
98+ }
99+ }
100+
101+ /// Gets the name of this enum case
102+ pub fn name ( & self ) -> & CStr {
103+ & self . case_name
104+ }
105+
106+ /// Gets the StateEnum this case belongs to
107+ pub fn enum_type ( & self ) -> StateEnum < T > {
108+ self . bound_enum . clone ( )
109+ }
110+
111+ /// Gets the corresponding enum case object instance
112+ ///
113+ /// This requires the enum to be fully registered in PHP.
114+ pub fn get_case_object ( & self ) -> crate :: Result < & StateObj < T > > {
115+ // Get the class entry for the enum
116+ let ce = self . bound_enum . as_class_entry ( ) ;
117+
118+ unsafe {
119+ // Find the case in the enum
120+ let case_zval = zend_enum_get_case_cstr ( ce. as_ptr ( ) as * mut _ , self . case_name . as_ptr ( ) ) ;
121+
122+ if case_zval. is_null ( ) {
123+ return Err ( crate :: Error :: boxed ( format ! (
124+ "Enum case {} not found in enum {}" ,
125+ self . case_name. to_string_lossy( ) ,
126+ self . enum_name. to_string_lossy( )
127+ ) ) ) ;
128+ }
129+
130+ // Convert to StateObj
131+ Ok ( StateObj :: < T > :: from_object_ptr ( phper_z_obj_p (
132+ case_zval as * const _ ,
133+ ) ) )
134+ }
135+ }
136+
137+ /// Gets the corresponding enum case object instance
138+ ///
139+ /// This requires the enum to be fully registered in PHP.
140+ pub fn get_mut_case_object ( & mut self ) -> crate :: Result < & mut StateObj < T > > {
141+ // Get the class entry for the enum
142+ let ce = self . bound_enum . as_class_entry ( ) ;
143+
144+ unsafe {
145+ // Find the case in the enum
146+ let case_zval = zend_enum_get_case_cstr ( ce. as_ptr ( ) as * mut _ , self . case_name . as_ptr ( ) ) ;
147+
148+ if case_zval. is_null ( ) {
149+ return Err ( crate :: Error :: boxed ( format ! (
150+ "Enum case {} not found in enum {}" ,
151+ self . case_name. to_string_lossy( ) ,
152+ self . enum_name. to_string_lossy( )
153+ ) ) ) ;
154+ }
155+
156+ // Convert to StateObj
157+ Ok ( StateObj :: < T > :: from_mut_object_ptr ( phper_z_obj_p (
158+ case_zval as * const _ ,
159+ ) ) )
160+ }
161+ }
162+ }
163+
164+ impl < T > Clone for StateEnumCase < T > {
165+ fn clone ( & self ) -> Self {
166+ Self {
167+ enum_name : self . enum_name . clone ( ) ,
168+ case_name : self . case_name . clone ( ) ,
169+ bound_enum : self . bound_enum . clone ( ) ,
170+ _p : PhantomData ,
171+ }
172+ }
173+ }
174+
85175/// Builder for registering an enum.
86176/// B is a backing type that implements EnumBackingType
87177pub struct EnumEntity < B : EnumBackingType , T : ?Sized > {
@@ -164,13 +254,14 @@ impl<B: EnumBackingType, T: 'static> EnumEntity<B, T> {
164254 ///
165255 /// # Returns
166256 ///
167- /// Returns `&mut Self` to allow method chaining
168- pub fn add_case ( & mut self , name : impl Into < String > , value : B ) -> & mut Self {
257+ /// Returns a reference to the created enum case
258+ pub fn add_case ( & mut self , name : impl Into < String > , value : B ) -> StateEnumCase < T > {
259+ let case_name = ensure_end_with_zero ( name) ;
169260 self . cases . push ( EnumCase {
170- name : ensure_end_with_zero ( name ) ,
261+ name : case_name . clone ( ) ,
171262 value : value. into ( ) ,
172263 } ) ;
173- self
264+ StateEnumCase :: new ( self . enum_name . clone ( ) , case_name , self . bound_enum . clone ( ) )
174265 }
175266
176267 /// Add member method to enum that can access the enum state.
0 commit comments