1
1
use crate :: convert:: { FromZval , FromZvalMut } ;
2
- use crate :: ffi:: zend_object_iterator;
2
+ use crate :: ffi:: { zend_object_iterator, ZEND_RESULT_CODE_SUCCESS } ;
3
3
use crate :: flags:: DataType ;
4
+ use crate :: prelude:: PhpResult ;
4
5
use crate :: types:: Zval ;
6
+ use crate :: zend:: ExecutorGlobals ;
5
7
use std:: fmt:: { Debug , Display , Formatter } ;
6
8
7
9
/// A PHP Iterator.
@@ -16,47 +18,55 @@ impl ZendIterator {
16
18
/// # Returns
17
19
///
18
20
/// Returns a iterator over the zend_object_iterator.
19
- pub fn iter ( & mut self ) -> Iter {
21
+ pub fn iter ( & mut self ) -> PhpResult < Iter > {
20
22
self . index = 0 ;
21
- self . rewind ( ) ;
23
+ self . rewind ( ) ? ;
22
24
23
- Iter { zi : self }
25
+ Ok ( Iter { zi : self } )
24
26
}
25
27
26
28
/// Check if the current position of the iterator is valid.
27
29
///
28
30
/// As an example this will call the user defined valid method of the ['\Iterator'] interface.
29
31
/// see <https://www.php.net/manual/en/iterator.valid.php>
30
- pub fn valid ( & mut self ) -> bool {
32
+ pub fn valid ( & mut self ) -> PhpResult < bool > {
31
33
if let Some ( valid) = unsafe { ( * self . funcs ) . valid } {
32
- unsafe { valid ( & mut * self ) != 0 }
34
+ let valid = unsafe { valid ( & mut * self ) == ZEND_RESULT_CODE_SUCCESS } ;
35
+
36
+ ExecutorGlobals :: throw_if_exception ( ) ?;
37
+
38
+ Ok ( valid)
33
39
} else {
34
- true
40
+ Ok ( true )
35
41
}
36
42
}
37
43
38
44
/// Rewind the iterator to the first element.
39
45
///
40
46
/// As an example this will call the user defined rewind method of the ['\Iterator'] interface.
41
47
/// see <https://www.php.net/manual/en/iterator.rewind.php>
42
- pub fn rewind ( & mut self ) {
48
+ pub fn rewind ( & mut self ) -> PhpResult < ( ) > {
43
49
if let Some ( rewind) = unsafe { ( * self . funcs ) . rewind } {
44
50
unsafe {
45
51
rewind ( & mut * self ) ;
46
52
}
47
53
}
54
+
55
+ ExecutorGlobals :: throw_if_exception ( )
48
56
}
49
57
50
58
/// Move the iterator forward to the next element.
51
59
///
52
60
/// As an example this will call the user defined next method of the ['\Iterator'] interface.
53
61
/// see <https://www.php.net/manual/en/iterator.next.php>
54
- pub fn move_forward ( & mut self ) {
62
+ pub fn move_forward ( & mut self ) -> PhpResult < ( ) > {
55
63
if let Some ( move_forward) = unsafe { ( * self . funcs ) . move_forward } {
56
64
unsafe {
57
65
move_forward ( & mut * self ) ;
58
66
}
59
67
}
68
+
69
+ ExecutorGlobals :: throw_if_exception ( )
60
70
}
61
71
62
72
/// Get the current data of the iterator.
@@ -65,11 +75,16 @@ impl ZendIterator {
65
75
///
66
76
/// Returns a reference to the current data of the iterator if available
67
77
/// , ['None'] otherwise.
68
- pub fn get_current_data < ' a > ( & mut self ) -> Option < & ' a Zval > {
69
- let get_current_data = unsafe { ( * self . funcs ) . get_current_data } ?;
78
+ pub fn get_current_data < ' a > ( & mut self ) -> PhpResult < Option < & ' a Zval > > {
79
+ let get_current_data = match unsafe { ( * self . funcs ) . get_current_data } {
80
+ Some ( get_current_data) => get_current_data,
81
+ None => return Ok ( None ) ,
82
+ } ;
70
83
let value = unsafe { & * get_current_data ( & mut * self ) } ;
71
84
72
- Some ( value)
85
+ ExecutorGlobals :: throw_if_exception ( ) ?;
86
+
87
+ Ok ( Some ( value) )
73
88
}
74
89
75
90
/// Get the current key of the iterator.
@@ -78,14 +93,21 @@ impl ZendIterator {
78
93
///
79
94
/// Returns a new ['Zval'] containing the current key of the iterator if available
80
95
/// , ['None'] otherwise.
81
- pub fn get_current_key ( & mut self ) -> Option < Zval > {
82
- let get_current_key = unsafe { ( * self . funcs ) . get_current_key } ?;
96
+ pub fn get_current_key ( & mut self ) -> PhpResult < Option < Zval > > {
97
+ let get_current_key = match unsafe { ( * self . funcs ) . get_current_key } {
98
+ Some ( get_current_key) => get_current_key,
99
+ None => return Ok ( None ) ,
100
+ } ;
101
+
83
102
let mut key = Zval :: new ( ) ;
103
+
84
104
unsafe {
85
105
get_current_key ( & mut * self , & mut key) ;
86
106
}
87
107
88
- Some ( key)
108
+ ExecutorGlobals :: throw_if_exception ( ) ?;
109
+
110
+ Ok ( Some ( key) )
89
111
}
90
112
}
91
113
@@ -142,31 +164,40 @@ pub struct Iter<'a> {
142
164
}
143
165
144
166
impl < ' a > Iterator for Iter < ' a > {
145
- type Item = ( IterKey , & ' a Zval ) ;
167
+ type Item = PhpResult < ( IterKey , & ' a Zval ) > ;
146
168
147
169
fn next ( & mut self ) -> Option < Self :: Item > {
148
170
// Call next when index > 0, so next is really called at the start of each iteration, which allow to work better with generator iterator
149
171
if self . zi . index > 0 {
150
- self . zi . move_forward ( ) ;
151
-
152
- if !self . zi . valid ( ) {
153
- return None ;
172
+ if let Err ( err) = self . zi . move_forward ( ) {
173
+ return Some ( Err ( err) ) ;
154
174
}
155
175
}
156
176
177
+ match self . zi . valid ( ) {
178
+ Err ( err) => return Some ( Err ( err) ) ,
179
+ Ok ( false ) => return None ,
180
+ Ok ( true ) => ( ) ,
181
+ }
182
+
157
183
self . zi . index += 1 ;
158
184
159
- let key = self . zi . get_current_key ( ) ;
160
- let value = self . zi . get_current_data ( ) ?;
161
185
let real_index = self . zi . index - 1 ;
162
186
163
- Some ( match key {
164
- Some ( key) => match IterKey :: from_zval ( & key) {
165
- Some ( key) => ( key, value) ,
166
- None => ( IterKey :: Long ( real_index) , value) ,
187
+ let key = match self . zi . get_current_key ( ) {
188
+ Err ( err) => return Some ( Err ( err) ) ,
189
+ Ok ( None ) => IterKey :: Long ( real_index) ,
190
+ Ok ( Some ( key) ) => match IterKey :: from_zval ( & key) {
191
+ Some ( key) => key,
192
+ None => IterKey :: Long ( real_index) ,
167
193
} ,
168
- None => ( IterKey :: Long ( real_index) , value) ,
169
- } )
194
+ } ;
195
+
196
+ match self . zi . get_current_data ( ) {
197
+ Err ( err) => Some ( Err ( err) ) ,
198
+ Ok ( None ) => None ,
199
+ Ok ( Some ( value) ) => Some ( Ok ( ( key, value) ) ) ,
200
+ }
170
201
}
171
202
}
172
203
0 commit comments