Skip to content

Commit c5da1a9

Browse files
committed
feat(enum): implement IntoZval and FromZval for enums
Refs: #178
1 parent 4d8e7aa commit c5da1a9

File tree

10 files changed

+579
-157
lines changed

10 files changed

+579
-157
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ skeptic = "0.13"
2525

2626
[build-dependencies]
2727
anyhow = "1"
28-
bindgen = "0.68.1"
28+
bindgen = "0.72"
2929
cc = "1.0"
3030
skeptic = "0.13"
3131

allowed_bindings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ bind! {
8888
zend_declare_property,
8989
zend_do_implement_interface,
9090
zend_enum_add_case,
91+
zend_enum_get_case,
9192
zend_enum_new,
9293
zend_execute_data,
9394
zend_function_entry,

build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ fn generate_bindings(defines: &[(&str, &str)], includes: &[PathBuf]) -> Result<S
234234
.no_copy("_zend_array")
235235
.no_debug("_zend_function_entry") // On Windows when the handler uses vectorcall, Debug cannot be derived so we do it in code.
236236
.layout_tests(env::var("EXT_PHP_RS_TEST").is_ok())
237-
.rust_target(RustTarget::Nightly);
237+
.rust_target(RustTarget::nightly());
238238

239239
for binding in ALLOWED_BINDINGS {
240240
bindgen = bindgen

crates/macros/src/enum_.rs

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,13 @@ pub fn parser(mut input: ItemEnum) -> Result<TokenStream> {
101101
}
102102
}
103103

104-
let enum_props = Enum {
105-
ident: &input.ident,
106-
attrs: php_attr,
104+
let enum_props = Enum::new(
105+
&input.ident,
106+
&php_attr,
107107
docs,
108108
cases,
109-
flags: None, // TODO: Implement flags support
110-
};
109+
None, // TODO: Implement flags support
110+
);
111111

112112
Ok(quote! {
113113
#[allow(dead_code)]
@@ -120,28 +120,45 @@ pub fn parser(mut input: ItemEnum) -> Result<TokenStream> {
120120
#[derive(Debug)]
121121
pub struct Enum<'a> {
122122
ident: &'a Ident,
123-
attrs: PhpEnumAttribute,
123+
name: String,
124124
docs: Vec<String>,
125125
cases: Vec<EnumCase>,
126-
// TODO: Implement flags support
127-
#[allow(dead_code)]
128126
flags: Option<String>,
129127
}
130128

131-
impl ToTokens for Enum<'_> {
132-
fn to_tokens(&self, tokens: &mut TokenStream) {
129+
impl<'a> Enum<'a> {
130+
fn new(
131+
ident: &'a Ident,
132+
attrs: &PhpEnumAttribute,
133+
docs: Vec<String>,
134+
cases: Vec<EnumCase>,
135+
flags: Option<String>,
136+
) -> Self {
137+
let name = attrs.rename.rename(ident.to_string(), RenameRule::Pascal);
138+
139+
Self {
140+
ident,
141+
name,
142+
docs,
143+
cases,
144+
flags,
145+
}
146+
}
147+
148+
fn registered_class(&self) -> TokenStream {
133149
let ident = &self.ident;
134-
let enum_name = self
135-
.attrs
136-
.rename
137-
.rename(ident.to_string(), RenameRule::Pascal);
138-
let flags = quote! { ::ext_php_rs::flags::ClassFlags::Enum };
150+
let name = &self.name;
151+
let flags = self
152+
.flags
153+
.as_ref()
154+
.map(|f| quote! { | #f })
155+
.unwrap_or_default();
156+
let flags = quote! { ::ext_php_rs::flags::ClassFlags::Enum #flags };
139157
let docs = &self.docs;
140-
let cases = &self.cases;
141158

142-
let class = quote! {
159+
quote! {
143160
impl ::ext_php_rs::class::RegisteredClass for #ident {
144-
const CLASS_NAME: &'static str = #enum_name;
161+
const CLASS_NAME: &'static str = #name;
145162
const BUILDER_MODIFIER: ::std::option::Option<
146163
fn(::ext_php_rs::builders::ClassBuilder) -> ::ext_php_rs::builders::ClassBuilder
147164
> = None;
@@ -186,14 +203,54 @@ impl ToTokens for Enum<'_> {
186203
::ext_php_rs::internal::class::PhpClassImplCollector::<Self>::default().get_constants()
187204
}
188205
}
189-
};
190-
let enum_impl = quote! {
191-
impl ::ext_php_rs::enum_::PhpEnum for #ident {
206+
}
207+
}
208+
209+
fn registered_enum(&self) -> TokenStream {
210+
let ident = &self.ident;
211+
let cases = &self.cases;
212+
let case_from_names = self.cases.iter().map(|case| {
213+
let ident = &case.ident;
214+
let name = &case.name;
215+
quote! {
216+
#name => Ok(Self::#ident)
217+
}
218+
});
219+
let case_to_names = self.cases.iter().map(|case| {
220+
let ident = &case.ident;
221+
let name = &case.name;
222+
quote! {
223+
Self::#ident => #name
224+
}
225+
});
226+
227+
quote! {
228+
impl ::ext_php_rs::enum_::RegisteredEnum for #ident {
192229
const CASES: &'static [::ext_php_rs::enum_::EnumCase] = &[
193230
#(#cases,)*
194231
];
232+
233+
fn from_name(name: &str) -> ::ext_php_rs::error::Result<Self> {
234+
match name {
235+
#(#case_from_names,)*
236+
_ => Err(::ext_php_rs::error::Error::InvalidProperty),
237+
}
238+
}
239+
240+
fn to_name(&self) -> &'static str {
241+
match self {
242+
#(#case_to_names,)*
243+
}
244+
}
195245
}
196-
};
246+
}
247+
}
248+
}
249+
250+
impl ToTokens for Enum<'_> {
251+
fn to_tokens(&self, tokens: &mut TokenStream) {
252+
let class = self.registered_class();
253+
let enum_impl = self.registered_enum();
197254

198255
tokens.extend(quote! {
199256
#class

0 commit comments

Comments
 (0)