Skip to content

Commit 6a0518f

Browse files
authored
Change ini entities cross threads. (#55)
1 parent d795cdd commit 6a0518f

File tree

8 files changed

+179
-170
lines changed

8 files changed

+179
-170
lines changed

examples/hello/src/lib.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ use phper::{
1212
arrays::ZArray,
1313
classes::{StatefulClass, Visibility},
1414
functions::Argument,
15-
ini::{Ini, Policy},
15+
ini::{ini_get, Policy},
1616
modules::{Module, ModuleContext},
1717
objects::StatefulObj,
1818
php_get_module,
1919
values::ZVal,
2020
};
21+
use std::ffi::CStr;
2122

2223
fn say_hello(arguments: &mut [ZVal]) -> phper::Result<String> {
2324
let name = &mut arguments[0];
@@ -39,10 +40,10 @@ pub fn get_module() -> Module {
3940
);
4041

4142
// register module ini
42-
Ini::add("hello.enable", false, Policy::All);
43-
Ini::add("hello.num", 100, Policy::All);
44-
Ini::add("hello.ratio", 1.5, Policy::All);
45-
Ini::add("hello.description", "hello world.".to_owned(), Policy::All);
43+
module.add_ini("hello.enable", false, Policy::All);
44+
module.add_ini("hello.num", 100, Policy::All);
45+
module.add_ini("hello.ratio", 1.5, Policy::All);
46+
module.add_ini("hello.description", "hello world.".to_owned(), Policy::All);
4647

4748
// register hook functions
4849
module.on_module_init(|_: ModuleContext| true);
@@ -58,10 +59,10 @@ pub fn get_module() -> Module {
5859
|_: &mut [ZVal]| {
5960
let mut arr = ZArray::new();
6061

61-
let hello_enable = ZVal::from(Ini::get::<bool>("hello.enable"));
62+
let hello_enable = ZVal::from(ini_get::<bool>("hello.enable"));
6263
arr.insert("hello.enable", hello_enable);
6364

64-
let hello_description = ZVal::from(Ini::get::<String>("hello.description"));
65+
let hello_description = ZVal::from(ini_get::<Option<&CStr>>("hello.description"));
6566
arr.insert("hello.description", hello_description);
6667

6768
arr

phper/src/ini.rs

Lines changed: 82 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -10,75 +10,19 @@
1010

1111
//! Apis relate to [crate::sys::zend_ini_entry_def].
1212
13-
use crate::sys::{
14-
phper_zend_ini_mh, zend_ini_entry_def, OnUpdateBool, OnUpdateLong, OnUpdateReal,
15-
OnUpdateString, PHP_INI_ALL, PHP_INI_PERDIR, PHP_INI_SYSTEM, PHP_INI_USER,
16-
};
17-
use dashmap::DashMap;
13+
use crate::sys::*;
1814
use std::{
19-
any::TypeId,
2015
ffi::CStr,
21-
mem::{size_of, zeroed},
22-
os::raw::{c_char, c_void},
16+
mem::{zeroed, ManuallyDrop},
17+
os::raw::c_char,
2318
ptr::null_mut,
2419
str,
25-
sync::atomic::{AtomicBool, Ordering},
2620
};
2721

28-
static REGISTERED: AtomicBool = AtomicBool::new(false);
29-
30-
thread_local! {
31-
static INI_ENTITIES: DashMap<String, IniEntity> = DashMap::new();
22+
pub fn ini_get<T: FromIniValue>(name: &str) -> T {
23+
T::from_ini_value(name)
3224
}
3325

34-
pub struct Ini;
35-
36-
impl Ini {
37-
pub fn add(name: impl Into<String>, default_value: impl TransformIniValue, policy: Policy) {
38-
assert!(
39-
!REGISTERED.load(Ordering::SeqCst),
40-
"shouldn't add ini after registered"
41-
);
42-
43-
let name = name.into();
44-
45-
INI_ENTITIES.with(|ini_entities| {
46-
ini_entities.insert(name.clone(), IniEntity::new(name, default_value, policy));
47-
});
48-
}
49-
50-
pub fn get<T: TransformIniValue>(name: &str) -> Option<T> {
51-
assert!(
52-
REGISTERED.load(Ordering::SeqCst),
53-
"shouldn't get ini before registered"
54-
);
55-
56-
INI_ENTITIES.with(|ini_entities| {
57-
ini_entities
58-
.get(name)
59-
.and_then(|entity| entity.value().value())
60-
})
61-
}
62-
63-
pub(crate) unsafe fn entries() -> *const zend_ini_entry_def {
64-
REGISTERED.store(true, Ordering::SeqCst);
65-
66-
let mut entries = Vec::new();
67-
68-
INI_ENTITIES.with(|ini_entities| {
69-
for mut entity in ini_entities.iter_mut() {
70-
entries.push(entity.value_mut().entry());
71-
}
72-
});
73-
74-
entries.push(zeroed::<zend_ini_entry_def>());
75-
76-
Box::into_raw(entries.into_boxed_slice()).cast()
77-
}
78-
}
79-
80-
pub type OnModify = phper_zend_ini_mh;
81-
8226
#[repr(u32)]
8327
#[derive(Copy, Clone)]
8428
pub enum Policy {
@@ -89,145 +33,109 @@ pub enum Policy {
8933
}
9034

9135
/// The Type which can transform to an ini value.
92-
///
93-
/// Be careful that the size of `arg2` must litter than size of `usize`.
94-
///
95-
/// TODO Add a size compare with usize trait bound, after const generic
96-
/// supports.
97-
pub trait TransformIniValue: Sized + ToString + 'static {
98-
fn on_modify() -> OnModify;
99-
100-
/// # Safety
101-
unsafe fn transform(data: usize) -> Option<Self>;
102-
103-
fn arg2_type() -> TypeId;
104-
105-
fn arg2_size() -> usize;
106-
107-
fn to_text(&self) -> String {
108-
self.to_string()
109-
}
36+
pub trait IntoIniValue {
37+
fn into_ini_value(self) -> String;
11038
}
11139

112-
impl TransformIniValue for bool {
113-
fn on_modify() -> OnModify {
114-
Some(OnUpdateBool)
115-
}
116-
117-
unsafe fn transform(data: usize) -> Option<Self> {
118-
Some(data != 0)
119-
}
120-
121-
fn arg2_type() -> TypeId {
122-
TypeId::of::<bool>()
123-
}
124-
125-
fn arg2_size() -> usize {
126-
size_of::<bool>()
40+
impl IntoIniValue for bool {
41+
#[inline]
42+
fn into_ini_value(self) -> String {
43+
if self {
44+
"1".to_owned()
45+
} else {
46+
"0".to_owned()
47+
}
12748
}
12849
}
12950

130-
impl TransformIniValue for i64 {
131-
fn on_modify() -> OnModify {
132-
Some(OnUpdateLong)
133-
}
134-
135-
unsafe fn transform(data: usize) -> Option<Self> {
136-
Some(data as i64)
137-
}
138-
139-
fn arg2_type() -> TypeId {
140-
TypeId::of::<i64>()
141-
}
142-
143-
fn arg2_size() -> usize {
144-
size_of::<i64>()
51+
impl IntoIniValue for i64 {
52+
#[inline]
53+
fn into_ini_value(self) -> String {
54+
self.to_string()
14555
}
14656
}
14757

148-
impl TransformIniValue for f64 {
149-
fn on_modify() -> OnModify {
150-
Some(OnUpdateReal)
151-
}
152-
153-
unsafe fn transform(data: usize) -> Option<Self> {
154-
Some(data as f64)
58+
impl IntoIniValue for f64 {
59+
#[inline]
60+
fn into_ini_value(self) -> String {
61+
self.to_string()
15562
}
63+
}
15664

157-
fn arg2_type() -> TypeId {
158-
TypeId::of::<i64>()
65+
impl IntoIniValue for String {
66+
#[inline]
67+
fn into_ini_value(self) -> String {
68+
self
15969
}
70+
}
16071

161-
fn arg2_size() -> usize {
162-
size_of::<i64>()
163-
}
72+
/// For php7, the zend_ini_* functions receive ini name as `*mut c_char`, but I
73+
/// think it's immutable.
74+
pub trait FromIniValue {
75+
fn from_ini_value(name: &str) -> Self;
16476
}
16577

166-
impl TransformIniValue for String {
167-
fn on_modify() -> OnModify {
168-
Some(OnUpdateString)
78+
impl FromIniValue for bool {
79+
fn from_ini_value(name: &str) -> Self {
80+
unsafe {
81+
let name_ptr = name.as_ptr() as *mut u8 as *mut c_char;
82+
zend_ini_long(name_ptr, name.len().try_into().unwrap(), 0) != 0
83+
}
16984
}
85+
}
17086

171-
unsafe fn transform(data: usize) -> Option<Self> {
172-
let ptr = data as *mut c_char;
173-
CStr::from_ptr(ptr).to_str().ok().map(|s| s.to_owned())
87+
impl FromIniValue for i64 {
88+
fn from_ini_value(name: &str) -> Self {
89+
unsafe {
90+
let name_ptr = name.as_ptr() as *mut u8 as *mut c_char;
91+
zend_ini_long(name_ptr, name.len().try_into().unwrap(), 0)
92+
}
17493
}
94+
}
17595

176-
fn arg2_type() -> TypeId {
177-
TypeId::of::<*mut c_char>()
96+
impl FromIniValue for f64 {
97+
fn from_ini_value(name: &str) -> Self {
98+
unsafe {
99+
let name_ptr = name.as_ptr() as *mut u8 as *mut c_char;
100+
zend_ini_double(name_ptr, name.len().try_into().unwrap(), 0)
101+
}
178102
}
103+
}
179104

180-
fn arg2_size() -> usize {
181-
size_of::<*mut c_char>()
105+
impl FromIniValue for Option<&CStr> {
106+
fn from_ini_value(name: &str) -> Self {
107+
unsafe {
108+
let name_ptr = name.as_ptr() as *mut u8 as *mut c_char;
109+
let ptr = zend_ini_string_ex(name_ptr, name.len().try_into().unwrap(), 0, null_mut());
110+
(!ptr.is_null()).then(|| CStr::from_ptr(ptr))
111+
}
182112
}
183113
}
184114

185115
pub(crate) struct IniEntity {
186116
name: String,
187-
value: usize,
188-
value_type_id: TypeId,
189117
default_value: String,
190-
on_modify: OnModify,
191118
policy: Policy,
192119
}
193120

194121
impl IniEntity {
195-
pub(crate) fn new<T: TransformIniValue>(
122+
pub(crate) fn new<T: IntoIniValue>(
196123
name: impl Into<String>, default_value: T, policy: Policy,
197124
) -> Self {
198-
assert!(<T>::arg2_size() <= size_of::<usize>());
199125
Self {
200126
name: name.into(),
201-
value: 0,
202-
value_type_id: <T>::arg2_type(),
203-
default_value: default_value.to_text(),
204-
on_modify: <T>::on_modify(),
127+
default_value: default_value.into_ini_value(),
205128
policy,
206129
}
207130
}
208131

209-
pub(crate) fn value<T: TransformIniValue>(&self) -> Option<T> {
210-
if self.value_type_id != <T>::arg2_type() {
211-
None
212-
} else {
213-
unsafe { <T>::transform(self.value) }
214-
}
215-
}
216-
132+
#[inline]
217133
pub(crate) fn entry(&mut self) -> zend_ini_entry_def {
218-
create_ini_entry_ex(
219-
&self.name,
220-
&self.default_value,
221-
self.on_modify,
222-
self.policy as u32,
223-
&mut self.value as *mut _ as *mut c_void,
224-
)
134+
create_ini_entry_ex(&self.name, &self.default_value, self.policy as u32)
225135
}
226136
}
227137

228-
pub(crate) fn create_ini_entry_ex(
229-
name: &str, default_value: &str, on_modify: OnModify, modifiable: u32, arg2: *mut c_void,
230-
) -> zend_ini_entry_def {
138+
fn create_ini_entry_ex(name: &str, default_value: &str, modifiable: u32) -> zend_ini_entry_def {
231139
#[cfg(any(
232140
phper_php_version = "8.1",
233141
phper_php_version = "8.0",
@@ -244,9 +152,9 @@ pub(crate) fn create_ini_entry_ex(
244152

245153
zend_ini_entry_def {
246154
name: name.as_ptr().cast(),
247-
on_modify,
155+
on_modify: None,
248156
mh_arg1: null_mut(),
249-
mh_arg2: arg2,
157+
mh_arg2: null_mut(),
250158
mh_arg3: null_mut(),
251159
value: default_value.as_ptr().cast(),
252160
displayer: None,
@@ -255,3 +163,17 @@ pub(crate) fn create_ini_entry_ex(
255163
value_length: default_value.len() as u32,
256164
}
257165
}
166+
167+
pub(crate) unsafe fn entries(ini_entries: Vec<IniEntity>) -> *const zend_ini_entry_def {
168+
let mut entries = Vec::with_capacity(ini_entries.len() + 1);
169+
170+
ini_entries.into_iter().for_each(|entity| {
171+
// Ini entity will exist throughout the whole application life cycle.
172+
let mut entity = ManuallyDrop::new(entity);
173+
entries.push(entity.entry());
174+
});
175+
176+
entries.push(zeroed::<zend_ini_entry_def>());
177+
178+
Box::into_raw(entries.into_boxed_slice()).cast()
179+
}

0 commit comments

Comments
 (0)