Skip to content

Commit 87e19d9

Browse files
committed
feat(macro): Add macro to declare interface from trait
1 parent 7e44ae2 commit 87e19d9

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

crates/macros/src/interface.rs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
use darling::util::Flag;
2+
use darling::{FromAttributes, FromMeta, ToTokens};
3+
use proc_macro2::TokenStream;
4+
use quote::{format_ident, quote};
5+
use syn::{Attribute, Expr, Fields, ItemStruct, ItemTrait};
6+
7+
use crate::helpers::get_docs;
8+
use crate::parsing::{PhpRename, RenameRule};
9+
use crate::prelude::*;
10+
11+
#[derive(FromAttributes, Debug, Default)]
12+
#[darling(attributes(php), forward_attrs(doc), default)]
13+
pub struct StructAttributes {
14+
#[darling(flatten)]
15+
rename: PhpRename,
16+
}
17+
18+
pub fn parser(mut input: ItemTrait) -> Result<TokenStream> {
19+
let attr = StructAttributes::from_attributes(&input.attrs)?;
20+
let ident = &input.ident;
21+
22+
let interface_name = format_ident!("PhpInterface{ident}");
23+
let name = attr.rename.rename(ident.to_string(), RenameRule::Pascal);
24+
25+
Ok(quote! {
26+
#input
27+
28+
pub struct #interface_name;
29+
30+
impl ::ext_php_rs::class::RegisteredClass for #interface_name {
31+
const CLASS_NAME: &'static str = #name;
32+
33+
const BUILDER_MODIFIER: Option<
34+
fn(::ext_php_rs::builders::ClassBuilder) -> ::ext_php_rs::builders::ClassBuilder,
35+
> = None;
36+
37+
const EXTENDS: Option<::ext_php_rs::class::ClassEntryInfo> = None;
38+
39+
const FLAGS: ::ext_php_rs::flags::ClassFlags = ::ext_php_rs::flags::ClassFlags::Interface;
40+
41+
const IMPLEMENTS: &'static [::ext_php_rs::class::ClassEntryInfo] = &[];
42+
43+
fn get_metadata() -> &'static ::ext_php_rs::class::ClassMetadata<Self> {
44+
static METADATA: ::ext_php_rs::class::ClassMetadata<#interface_name> =
45+
::ext_php_rs::class::ClassMetadata::new();
46+
47+
&METADATA
48+
}
49+
50+
fn method_builders() -> Vec<(
51+
::ext_php_rs::builders::FunctionBuilder<'static>,
52+
::ext_php_rs::flags::MethodFlags,
53+
)> {
54+
vec![ ]
55+
}
56+
57+
fn constructor() -> Option<::ext_php_rs::class::ConstructorMeta<Self>> {
58+
None
59+
}
60+
61+
fn constants() -> &'static [(
62+
&'static str,
63+
&'static dyn ext_php_rs::convert::IntoZvalDyn,
64+
ext_php_rs::describe::DocComments,
65+
)] {
66+
&[]
67+
}
68+
69+
fn get_properties<'a>() -> std::collections::HashMap<&'static str, PropertyInfo<'a, Self>> {
70+
HashMap::new()
71+
}
72+
73+
}
74+
75+
impl<'a> ::ext_php_rs::convert::FromZendObject<'a> for &'a #interface_name {
76+
#[inline]
77+
fn from_zend_object(
78+
obj: &'a ::ext_php_rs::types::ZendObject,
79+
) -> ::ext_php_rs::error::Result<Self> {
80+
let obj = ::ext_php_rs::types::ZendClassObject::<#interface_name>::from_zend_obj(obj)
81+
.ok_or(::ext_php_rs::error::Error::InvalidScope)?;
82+
Ok(&**obj)
83+
}
84+
}
85+
impl<'a> ::ext_php_rs::convert::FromZendObjectMut<'a> for &'a mut #interface_name {
86+
#[inline]
87+
fn from_zend_object_mut(
88+
obj: &'a mut ::ext_php_rs::types::ZendObject,
89+
) -> ::ext_php_rs::error::Result<Self> {
90+
let obj = ::ext_php_rs::types::ZendClassObject::<#interface_name>::from_zend_obj_mut(obj)
91+
.ok_or(::ext_php_rs::error::Error::InvalidScope)?;
92+
Ok(&mut **obj)
93+
}
94+
}
95+
impl<'a> ::ext_php_rs::convert::FromZval<'a> for &'a #interface_name {
96+
const TYPE: ::ext_php_rs::flags::DataType = ::ext_php_rs::flags::DataType::Object(Some(
97+
<#interface_name as ::ext_php_rs::class::RegisteredClass>::CLASS_NAME,
98+
));
99+
#[inline]
100+
fn from_zval(zval: &'a ::ext_php_rs::types::Zval) -> ::std::option::Option<Self> {
101+
<Self as ::ext_php_rs::convert::FromZendObject>::from_zend_object(zval.object()?).ok()
102+
}
103+
}
104+
impl<'a> ::ext_php_rs::convert::FromZvalMut<'a> for &'a mut #interface_name {
105+
const TYPE: ::ext_php_rs::flags::DataType = ::ext_php_rs::flags::DataType::Object(Some(
106+
<#interface_name as ::ext_php_rs::class::RegisteredClass>::CLASS_NAME,
107+
));
108+
#[inline]
109+
fn from_zval_mut(zval: &'a mut ::ext_php_rs::types::Zval) -> ::std::option::Option<Self> {
110+
<Self as ::ext_php_rs::convert::FromZendObjectMut>::from_zend_object_mut(zval.object_mut()?)
111+
.ok()
112+
}
113+
}
114+
impl ::ext_php_rs::convert::IntoZendObject for #interface_name {
115+
#[inline]
116+
fn into_zend_object(
117+
self,
118+
) -> ::ext_php_rs::error::Result<::ext_php_rs::boxed::ZBox<::ext_php_rs::types::ZendObject>>
119+
{
120+
Ok(::ext_php_rs::types::ZendClassObject::new(self).into())
121+
}
122+
}
123+
impl ::ext_php_rs::convert::IntoZval for #interface_name {
124+
const TYPE: ::ext_php_rs::flags::DataType = ::ext_php_rs::flags::DataType::Object(Some(
125+
<#interface_name as ::ext_php_rs::class::RegisteredClass>::CLASS_NAME,
126+
));
127+
const NULLABLE: bool = false;
128+
#[inline]
129+
fn set_zval(
130+
self,
131+
zv: &mut ::ext_php_rs::types::Zval,
132+
persistent: bool,
133+
) -> ::ext_php_rs::error::Result<()> {
134+
use ::ext_php_rs::convert::IntoZendObject;
135+
self.into_zend_object()?.set_zval(zv, persistent)
136+
}
137+
}
138+
})
139+
}

crates/macros/src/lib.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,22 @@ mod fastcall;
77
mod function;
88
mod helpers;
99
mod impl_;
10+
mod interface;
1011
mod module;
1112
mod parsing;
1213
mod syn_ext;
1314
mod zval;
1415

1516
use proc_macro::TokenStream;
17+
<<<<<<< HEAD
1618
use proc_macro2::TokenStream as TokenStream2;
1719
use syn::{DeriveInput, ItemConst, ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemStruct};
20+
=======
21+
use syn::{
22+
parse_macro_input, DeriveInput, ItemConst, ItemFn, ItemForeignMod, ItemImpl, ItemStruct,
23+
ItemTrait,
24+
};
25+
>>>>>>> 1a0a9d6 (feat(macro): Add macro to declare interface from trait)
1826

1927
extern crate proc_macro;
2028

@@ -339,6 +347,21 @@ fn php_enum_internal(_args: TokenStream2, input: TokenStream2) -> TokenStream2 {
339347
enum_::parser(input).unwrap_or_else(|e| e.to_compile_error())
340348
}
341349

350+
#[proc_macro_attribute]
351+
pub fn php_interface(args: TokenStream, input: TokenStream) -> TokenStream {
352+
let input = parse_macro_input!(input as ItemTrait);
353+
354+
if !args.is_empty() {
355+
return err!(input => "`#[php_interface]` not apply args")
356+
.to_compile_error()
357+
.into();
358+
}
359+
360+
interface::parser(input)
361+
.unwrap_or_else(|e| e.to_compile_error())
362+
.into()
363+
}
364+
342365
// BEGIN DOCS FROM function.md
343366
/// # `#[php_function]` Attribute
344367
///

0 commit comments

Comments
 (0)