Skip to content

Commit 3b3de01

Browse files
committed
Refactoring ini.
1 parent db64f74 commit 3b3de01

File tree

8 files changed

+224
-163
lines changed

8 files changed

+224
-163
lines changed

examples/hello/src/lib.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ pub fn get_module() -> Module {
3131
);
3232

3333
// register module ini
34-
module.add_bool_ini("hello.enable", false, Policy::All);
35-
module.add_long_ini("hello.num", 100, Policy::All);
36-
module.add_real_ini("hello.ratio", 1.5, Policy::All);
37-
module.add_str_ini("hello.description", "hello world.", Policy::All);
34+
module.add_ini("hello.enable", false, Policy::All);
35+
module.add_ini("hello.num", 100, Policy::All);
36+
module.add_ini("hello.ratio", 1.5, Policy::All);
37+
module.add_ini("hello.description", "hello world.".to_owned(), Policy::All);
3838

3939
// register hook functions
4040
module.on_module_init(module_init);
@@ -50,10 +50,10 @@ pub fn get_module() -> Module {
5050
|_: &mut [Val]| {
5151
let mut arr = Array::new();
5252

53-
let hello_enable = Val::new(Module::get_bool_ini("hello.enable"));
53+
let hello_enable = Val::new(Module::get_ini::<bool>("hello.enable"));
5454
arr.insert("hello.enable", hello_enable);
5555

56-
let hello_description = Val::new(Module::get_str_ini("hello.description"));
56+
let hello_description = Val::new(Module::get_ini::<String>("hello.description"));
5757
arr.insert("hello.description", hello_description);
5858

5959
arr
@@ -63,7 +63,8 @@ pub fn get_module() -> Module {
6363

6464
// register classes
6565
let mut foo_class = DynamicClass::new("FooClass");
66-
foo_class.add_property("foo", Visibility::Public, "100".to_string());
66+
// foo_class.add_property("foo", Visibility::Public, 100);
67+
foo_class.add_property("foo", Visibility::Public, 100);
6768
foo_class.add_method(
6869
"getFoo",
6970
Visibility::Public,

examples/hello/tests/php/test.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@
1212
assert_eq($e->getMessage(), "I am sorry");
1313
}
1414

15+
var_dump(ini_get_all());
16+
die();
17+
1518
assert_eq(hello_get_all_ini(), [
1619
"hello.enable" => false,
1720
"hello.description" => "hello world.",
1821
]);
1922

2023
$foo = new FooClass();
21-
// TODO change '100' to 100.
22-
assert_eq($foo->getFoo(), '100');
24+
assert_eq($foo->getFoo(), 100);
2325

2426
$foo->setFoo("Hello");
2527
assert_eq($foo->getFoo(), "Hello");

phper/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ keywords = ["php", "binding", "extension"]
1616
anyhow = "1.0.40"
1717
clap = "3.0.0-beta.2"
1818
dashmap = "4.0.2"
19+
derive_more = "0.99.13"
1920
indexmap = "1.6.2"
2021
num-derive = "0.3"
2122
num-traits = "0.2"

phper/src/classes.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
functions::{Argument, Function, FunctionEntity, FunctionEntry, Method},
77
objects::{ExtendObject, Object},
88
sys::*,
9+
types::Scalar,
910
values::{SetVal, Val},
1011
};
1112
use dashmap::DashMap;
@@ -118,11 +119,15 @@ impl<T: Send + 'static> DynamicClass<T> {
118119
));
119120
}
120121

121-
pub fn add_property(
122+
/// Declare property.
123+
///
124+
/// The argument `value` should be `Copy` because 'zend_declare_property' receive only scalar
125+
/// zval , otherwise will report fatal error: "Internal zvals cannot be refcounted".
126+
pub fn add_property<'a>(
122127
&mut self,
123128
name: impl ToString,
124129
vis: Visibility,
125-
value: impl SetVal + Clone,
130+
value: impl Into<Scalar<'a>>,
126131
) {
127132
self.property_entities
128133
.push(PropertyEntity::new(name, vis, value));
@@ -281,7 +286,7 @@ impl ClassEntity {
281286
let properties = self.classifiable.properties();
282287
for property in properties {
283288
let val = replace(&mut property.value, None).unwrap();
284-
zend_declare_property_string(
289+
zend_declare_property(
285290
self.entry.load(Ordering::SeqCst).cast(),
286291
property.name.as_ptr().cast(),
287292
property.name.len(),
@@ -327,11 +332,15 @@ pub struct PropertyEntity {
327332
}
328333

329334
impl PropertyEntity {
330-
pub fn new(name: impl ToString, visibility: Visibility, value: impl SetVal) -> Self {
335+
pub fn new<'a>(
336+
name: impl ToString,
337+
visibility: Visibility,
338+
value: impl Into<Scalar<'a>>,
339+
) -> Self {
331340
Self {
332341
name: name.to_string(),
333342
visibility,
334-
value: Some(EBox::new(Val::new(value))),
343+
value: Some(EBox::new(Val::new(value.into()))),
335344
}
336345
}
337346
}

phper/src/ini.rs

Lines changed: 154 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,65 @@
11
//! Apis relate to [crate::sys::zend_ini_entry_def].
22
3-
use crate::sys::{
4-
phper_zend_ini_mh, zend_ini_entry_def, OnUpdateBool, OnUpdateLong, OnUpdateReal,
5-
OnUpdateString, PHP_INI_ALL, PHP_INI_PERDIR, PHP_INI_SYSTEM, PHP_INI_USER,
3+
use crate::{
4+
errors::Error::Type,
5+
sys::{
6+
phper_zend_ini_mh, zend_ini_entry_def, OnUpdateBool, OnUpdateLong, OnUpdateReal,
7+
OnUpdateString, PHP_INI_ALL, PHP_INI_PERDIR, PHP_INI_SYSTEM, PHP_INI_USER,
8+
},
69
};
10+
use dashmap::DashMap;
11+
use derive_more::{From, TryInto};
712
use std::{
13+
any::{Any, TypeId},
14+
collections::HashMap,
15+
convert::TryFrom,
816
ffi::CStr,
17+
mem::{size_of, transmute, transmute_copy, zeroed},
918
os::raw::{c_char, c_void},
1019
ptr::null_mut,
1120
str,
1221
};
1322

14-
type OnModify = phper_zend_ini_mh;
23+
pub struct Ini;
24+
25+
impl Ini {
26+
thread_local! {
27+
static INI_ENTITIES: DashMap<String, IniEntity> = DashMap::new();
28+
}
29+
30+
pub fn add(name: impl ToString, default_value: impl TransformIniValue, policy: Policy) {
31+
Self::INI_ENTITIES.with(|ini_entities| {
32+
ini_entities.insert(
33+
name.to_string(),
34+
IniEntity::new(name, default_value, policy),
35+
);
36+
});
37+
}
38+
39+
fn get<T: TransformIniValue>(name: &str) -> Option<T> {
40+
Self::INI_ENTITIES.with(|ini_entities| {
41+
ini_entities
42+
.get(name)
43+
.and_then(|entity| entity.value().value())
44+
})
45+
}
46+
47+
pub(crate) unsafe fn entries() -> *const zend_ini_entry_def {
48+
let mut entries = Vec::new();
49+
50+
Self::INI_ENTITIES.with(|ini_entities| {
51+
for entity in ini_entities {
52+
entries.push(entity.value().entry());
53+
}
54+
});
55+
56+
entries.push(zeroed::<zend_ini_entry_def>());
57+
58+
Box::into_raw(entries.into_boxed_slice()).cast()
59+
}
60+
}
61+
62+
pub type OnModify = phper_zend_ini_mh;
1563

1664
#[repr(u32)]
1765
#[derive(Copy, Clone)]
@@ -22,89 +70,147 @@ pub enum Policy {
2270
System = PHP_INI_SYSTEM,
2371
}
2472

25-
pub(crate) struct StrPtrBox {
26-
inner: Box<*mut c_char>,
27-
}
73+
pub trait TransformIniValue: ToString + 'static {
74+
fn on_modify(&self) -> OnModify;
75+
76+
unsafe fn transform(&self, data: usize) -> Option<*mut c_void>;
77+
78+
fn arg2_type(&self) -> TypeId;
2879

29-
impl StrPtrBox {
30-
pub(crate) unsafe fn to_string(&self) -> Result<String, str::Utf8Error> {
31-
Ok(CStr::from_ptr(*self.inner).to_str()?.to_string())
80+
fn arg2_size(&self) -> usize;
81+
82+
fn to_text(&self) -> String {
83+
self.to_string()
3284
}
3385
}
3486

35-
impl Default for StrPtrBox {
36-
fn default() -> Self {
37-
Self {
38-
inner: Box::new(null_mut()),
39-
}
87+
impl TransformIniValue for bool {
88+
fn on_modify(&self) -> OnModify {
89+
Some(OnUpdateBool)
4090
}
41-
}
4291

43-
pub trait IniValue: Default {
44-
fn on_modify() -> OnModify;
92+
unsafe fn transform(&self, data: usize) -> Option<*mut c_void> {
93+
let b = data != 0;
94+
Some(Box::into_raw(Box::new(b)).cast())
95+
}
4596

46-
fn arg2(&mut self) -> *mut c_void {
47-
&mut *self as *mut _ as *mut c_void
97+
fn arg2_type(&self) -> TypeId {
98+
TypeId::of::<bool>()
4899
}
49-
}
50100

51-
impl IniValue for bool {
52-
fn on_modify() -> OnModify {
53-
Some(OnUpdateBool)
101+
fn arg2_size(&self) -> usize {
102+
size_of::<bool>()
54103
}
55104
}
56105

57-
impl IniValue for i64 {
58-
fn on_modify() -> OnModify {
106+
impl TransformIniValue for i64 {
107+
fn on_modify(&self) -> OnModify {
59108
Some(OnUpdateLong)
60109
}
110+
111+
unsafe fn transform(&self, data: usize) -> Option<*mut c_void> {
112+
let i = data as i64;
113+
Some(Box::into_raw(Box::new(i)).cast())
114+
}
115+
116+
fn arg2_type(&self) -> TypeId {
117+
TypeId::of::<i64>()
118+
}
119+
120+
fn arg2_size(&self) -> usize {
121+
size_of::<i64>()
122+
}
61123
}
62124

63-
impl IniValue for f64 {
64-
fn on_modify() -> OnModify {
125+
impl TransformIniValue for f64 {
126+
fn on_modify(&self) -> OnModify {
65127
Some(OnUpdateReal)
66128
}
129+
130+
unsafe fn transform(&self, data: usize) -> Option<*mut c_void> {
131+
let f = data as f64;
132+
Some(Box::into_raw(Box::new(f)).cast())
133+
}
134+
135+
fn arg2_type(&self) -> TypeId {
136+
TypeId::of::<i64>()
137+
}
138+
139+
fn arg2_size(&self) -> usize {
140+
size_of::<i64>()
141+
}
67142
}
68143

69-
impl IniValue for StrPtrBox {
70-
fn on_modify() -> OnModify {
144+
impl TransformIniValue for String {
145+
fn on_modify(&self) -> OnModify {
71146
Some(OnUpdateString)
72147
}
73148

74-
fn arg2(&mut self) -> *mut c_void {
75-
Box::as_mut(&mut self.inner) as *mut _ as *mut c_void
149+
unsafe fn transform(&self, data: usize) -> Option<*mut c_void> {
150+
let ptr = data as *mut c_char;
151+
CStr::from_ptr(ptr)
152+
.to_str()
153+
.ok()
154+
.map(|s| Box::into_raw(Box::new(s.to_owned())).cast())
155+
}
156+
157+
fn arg2_type(&self) -> TypeId {
158+
TypeId::of::<*mut c_char>()
159+
}
160+
161+
fn arg2_size(&self) -> usize {
162+
size_of::<*mut c_char>()
76163
}
77164
}
78165

79-
pub(crate) struct IniEntity<T: IniValue> {
166+
pub(crate) struct IniEntity {
80167
name: String,
81-
value: T,
168+
value: usize,
82169
default_value: String,
170+
transform: Box<dyn TransformIniValue>,
83171
policy: Policy,
84172
}
85173

86-
impl<T: IniValue> IniEntity<T> {
87-
pub(crate) fn new(name: impl ToString, default_value: impl ToString, policy: Policy) -> Self {
174+
impl IniEntity {
175+
pub(crate) fn new<T: TransformIniValue>(
176+
name: impl ToString,
177+
default_value: T,
178+
policy: Policy,
179+
) -> Self {
180+
assert!(default_value.arg2_size() <= size_of::<usize>());
88181
Self {
89182
name: name.to_string(),
90-
value: Default::default(),
91-
default_value: default_value.to_string(),
183+
value: 0,
184+
default_value: default_value.to_text(),
185+
transform: Box::new(default_value),
92186
policy,
93187
}
94188
}
95189

96-
pub(crate) fn value(&self) -> &T {
97-
&self.value
190+
pub(crate) fn value<T: TransformIniValue>(&self) -> Option<T> {
191+
if self.transform.arg2_type() != TypeId::of::<T>() {
192+
None
193+
} else {
194+
unsafe {
195+
let ptr = self.transform.transform(self.value);
196+
ptr.map(|ptr| {
197+
let b = Box::from_raw(ptr as *mut T);
198+
*b
199+
})
200+
}
201+
}
98202
}
99203

100-
pub(crate) unsafe fn ini_entry_def(&mut self) -> zend_ini_entry_def {
101-
create_ini_entry_ex(
102-
&self.name,
103-
&self.default_value,
104-
<T>::on_modify(),
105-
self.policy as u32,
106-
self.value.arg2(),
107-
)
204+
pub(crate) fn entry(&mut self) -> zend_ini_entry_def {
205+
unsafe {
206+
create_ini_entry_ex(
207+
&self.name,
208+
&self.default_value,
209+
self.transform.on_modify(),
210+
self.policy as u32,
211+
&mut self.value as *mut _ as *mut c_void,
212+
)
213+
}
108214
}
109215
}
110216

0 commit comments

Comments
 (0)