Skip to content

Commit 2e8f3a3

Browse files
committed
Add enum
1 parent eb34538 commit 2e8f3a3

File tree

2 files changed

+105
-14
lines changed

2 files changed

+105
-14
lines changed

phper/src/enums.rs

Lines changed: 103 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313

1414
use 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;
2828
use 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
87177
pub 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.

phper/src/modules.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use crate::{
1414
classes::{ClassEntity, Interface, InterfaceEntity, StateClass},
1515
constants::Constant,
16-
enums::{EnumEntity, StateEnum},
16+
enums::EnumEntity,
1717
errors::Throwable,
1818
functions::{Function, FunctionEntity, FunctionEntry, HandlerMap},
1919
ini,
@@ -63,7 +63,7 @@ unsafe extern "C" fn module_startup(_type: c_int, module_number: c_int) -> c_int
6363
}
6464

6565
for enum_entity in &module.enum_entities {
66-
let ce = enum_entity.init();
66+
enum_entity.init();
6767
module.handler_map.extend(enum_entity.handler_map());
6868
}
6969

0 commit comments

Comments
 (0)