@@ -20,8 +20,15 @@ pub enum CError {
20
20
type GameSizeType = minesweeper:: SizeType ;
21
21
type ArraySizeType = u64 ;
22
22
23
- macro_rules! return_error {
23
+ fn panic_if_null ( c_ei_ptr : * const CErrorInfo ) {
24
+ if c_ei_ptr. is_null ( ) {
25
+ panic ! ( "Error info ptr is null!" )
26
+ }
27
+ }
28
+
29
+ macro_rules! populate_error {
24
30
( $error_info_ptr: ident, $error_code: expr, $error_msg: expr) => { {
31
+ panic_if_null( $error_info_ptr) ;
25
32
let error_info = unsafe { & mut * $error_info_ptr } ;
26
33
if $error_msg. len( ) > 0 && error_info. error_message_max_length > 0 {
27
34
let ref error_message = $error_msg;
@@ -44,6 +51,12 @@ macro_rules! return_error {
44
51
}
45
52
}
46
53
error_info. error_code = $error_code;
54
+ } } ;
55
+ }
56
+
57
+ macro_rules! return_error {
58
+ ( $error_info_ptr: ident, $error_code: expr, $error_msg: expr) => { {
59
+ populate_error!( $error_info_ptr, $error_code, $error_msg) ;
47
60
return ;
48
61
} } ;
49
62
( $error_info_ptr: ident, $error_code: expr) => {
@@ -70,12 +83,33 @@ macro_rules! return_or_assign {
70
83
71
84
macro_rules! initialize_to_ok {
72
85
( $error_info_ptr: ident) => {
86
+ panic_if_null( $error_info_ptr) ;
73
87
let mut error_info = unsafe { & mut * $error_info_ptr } ;
74
88
error_info. error_code = CError :: Ok ;
75
89
error_info. error_message_length = 0 ;
76
90
} ;
77
91
}
78
92
93
+ macro_rules! get_mut_ref_from_ptr {
94
+ ( $ptr: ident, $error_info_ptr: ident) => {
95
+ if $ptr. is_null( ) {
96
+ return_error!( $error_info_ptr, CError :: NullPointerAsInput ) ;
97
+ } else {
98
+ unsafe { & mut * $ptr }
99
+ }
100
+ } ;
101
+ }
102
+
103
+ macro_rules! get_ref_from_ptr {
104
+ ( $ptr: ident, $error_info_ptr: ident) => {
105
+ if $ptr. is_null( ) {
106
+ return_error!( $error_info_ptr, CError :: NullPointerAsInput ) ;
107
+ } else {
108
+ unsafe { & * $ptr }
109
+ }
110
+ } ;
111
+ }
112
+
79
113
// Based on this https://s3.amazonaws.com/temp.michaelfbryan.com/objects/index.html
80
114
#[ repr( C ) ]
81
115
pub struct COpenedField {
@@ -110,7 +144,7 @@ pub extern "C" fn minesweeper_new_game(
110
144
if game_ptr_ptr. is_null ( ) {
111
145
return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
112
146
}
113
- let game_ptr = unsafe { & mut * game_ptr_ptr } ;
147
+ let game_ptr = get_mut_ref_from_ptr ! ( game_ptr_ptr, c_ei_ptr ) ;
114
148
if !game_ptr. is_null ( ) {
115
149
return_error ! ( c_ei_ptr, CError :: InvalidInput ) ;
116
150
}
@@ -127,11 +161,9 @@ pub extern "C" fn minesweeper_game_open(
127
161
c_ei_ptr : * mut CErrorInfo ,
128
162
) {
129
163
initialize_to_ok ! ( c_ei_ptr) ;
130
- if game_ptr. is_null ( ) || c_open_info_ptr. is_null ( ) {
131
- return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
132
- }
164
+ let game = get_mut_ref_from_ptr ! ( game_ptr, c_ei_ptr) ;
165
+ let c_open_info = get_mut_ref_from_ptr ! ( c_open_info_ptr, c_ei_ptr) ;
133
166
134
- let mut c_open_info = unsafe { & mut * c_open_info_ptr } ;
135
167
if c_open_info. newly_opened_fields_length != 0 {
136
168
return_error ! ( c_ei_ptr, CError :: InvalidInput ) ;
137
169
}
@@ -142,7 +174,6 @@ pub extern "C" fn minesweeper_game_open(
142
174
return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
143
175
}
144
176
145
- let game = unsafe { & mut * game_ptr } ;
146
177
let open_info = return_or_assign ! ( game. open( row, column) , c_ei_ptr) ;
147
178
148
179
if open_info. newly_opened_fields . len ( ) as ArraySizeType
@@ -176,11 +207,8 @@ pub extern "C" fn minesweeper_game_toggle_flag(
176
207
c_ei_ptr : * mut CErrorInfo ,
177
208
) {
178
209
initialize_to_ok ! ( c_ei_ptr) ;
179
- if game_ptr. is_null ( ) || field_flag_result_ptr. is_null ( ) {
180
- return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
181
- }
182
- let game = unsafe { & mut * game_ptr } ;
183
- let flag_result = unsafe { & mut * field_flag_result_ptr } ;
210
+ let game = get_mut_ref_from_ptr ! ( game_ptr, c_ei_ptr) ;
211
+ let flag_result = get_mut_ref_from_ptr ! ( field_flag_result_ptr, c_ei_ptr) ;
184
212
* flag_result = return_or_assign ! ( game. toggle_flag( row, column) , c_ei_ptr) ;
185
213
}
186
214
@@ -190,10 +218,7 @@ pub extern "C" fn minesweeper_destroy_game(
190
218
c_ei_ptr : * mut CErrorInfo ,
191
219
) {
192
220
initialize_to_ok ! ( c_ei_ptr) ;
193
- if game_ptr_ptr. is_null ( ) {
194
- return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
195
- }
196
- let game_ptr = unsafe { & mut * game_ptr_ptr } ;
221
+ let game_ptr = get_mut_ref_from_ptr ! ( game_ptr_ptr, c_ei_ptr) ;
197
222
if game_ptr. is_null ( ) {
198
223
return ;
199
224
}
@@ -213,8 +238,8 @@ pub extern "C" fn minesweeper_game_get_width(
213
238
if game_ptr. is_null ( ) || width_ptr. is_null ( ) {
214
239
return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
215
240
}
216
- let game = unsafe { & * game_ptr } ;
217
- let width = unsafe { & mut * width_ptr } ;
241
+ let game = get_ref_from_ptr ! ( game_ptr, c_ei_ptr ) ;
242
+ let width = get_mut_ref_from_ptr ! ( width_ptr, c_ei_ptr ) ;
218
243
* width = game. width ( ) ;
219
244
}
220
245
@@ -228,8 +253,8 @@ pub extern "C" fn minesweeper_game_get_height(
228
253
if game_ptr. is_null ( ) || height_ptr. is_null ( ) {
229
254
return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
230
255
}
231
- let game = unsafe { & * game_ptr } ;
232
- let height = unsafe { & mut * height_ptr } ;
256
+ let game = get_ref_from_ptr ! ( game_ptr, c_ei_ptr ) ;
257
+ let height = get_mut_ref_from_ptr ! ( height_ptr, c_ei_ptr ) ;
233
258
* height = game. height ( ) ;
234
259
}
235
260
@@ -243,8 +268,8 @@ pub extern "C" fn minesweeper_game_get_elapsed_seconds(
243
268
if game_ptr. is_null ( ) || elapsed_seconds_ptr. is_null ( ) {
244
269
return_error ! ( c_ei_ptr, CError :: NullPointerAsInput ) ;
245
270
}
246
- let game = unsafe { & * game_ptr } ;
247
- let elapsed_seconds = unsafe { & mut * elapsed_seconds_ptr } ;
271
+ let game = get_ref_from_ptr ! ( game_ptr, c_ei_ptr ) ;
272
+ let elapsed_seconds = get_mut_ref_from_ptr ! ( elapsed_seconds_ptr, c_ei_ptr ) ;
248
273
let elapsed_duration = game. get_elapsed ( ) ;
249
274
* elapsed_seconds = elapsed_duration. as_secs ( ) ;
250
275
}
@@ -400,7 +425,15 @@ mod test {
400
425
}
401
426
402
427
#[ test]
403
- fn destroy_game_with_nullptr ( ) {
428
+ #[ should_panic( expected = "Error info ptr is null!" ) ]
429
+ fn new_game_with_nullptr_as_error_info_ptr ( ) {
430
+ let level = GameLevel :: Beginner ;
431
+ let mut game_ptr: * mut Game = std:: ptr:: null_mut ( ) ;
432
+ minesweeper_new_game ( & mut game_ptr, level, std:: ptr:: null_mut ( ) ) ;
433
+ }
434
+
435
+ #[ test]
436
+ fn destroy_game_with_nullptr_as_game ( ) {
404
437
let mut error_info = create_empty_error_info ( ) ;
405
438
minesweeper_destroy_game ( std:: ptr:: null_mut ( ) , & mut error_info) ;
406
439
assert_eq ! ( CError :: NullPointerAsInput , error_info. error_code) ;
@@ -415,6 +448,13 @@ mod test {
415
448
check_no_error ( & error_info) ;
416
449
}
417
450
451
+ #[ test]
452
+ #[ should_panic( expected = "Error info ptr is null!" ) ]
453
+ fn destroy_game_with_nullptr_as_error_info_ptr ( ) {
454
+ let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
455
+ minesweeper_destroy_game ( & mut game_ptr, std:: ptr:: null_mut ( ) ) ;
456
+ }
457
+
418
458
#[ test]
419
459
fn create_and_destroy ( ) {
420
460
let mut error_info = create_empty_error_info ( ) ;
@@ -499,6 +539,20 @@ mod test {
499
539
destroy_game ( & mut game_ptr) ;
500
540
}
501
541
542
+ #[ test]
543
+ #[ should_panic( expected = "Error info ptr is null!" ) ]
544
+ fn open_with_nullptr_as_error_info_ptr ( ) {
545
+ let game_ptr = create_game ( GameLevel :: Beginner ) ;
546
+ let mut buffered_open_info = create_open_info_with_size ( 5 ) ;
547
+ minesweeper_game_open (
548
+ game_ptr,
549
+ 0 ,
550
+ 0 ,
551
+ & mut buffered_open_info. data ,
552
+ std:: ptr:: null_mut ( ) ,
553
+ ) ;
554
+ }
555
+
502
556
#[ test]
503
557
fn open_with_not_empty_newly_opened_fields ( ) {
504
558
let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
@@ -647,6 +701,14 @@ mod test {
647
701
destroy_game ( & mut game_ptr) ;
648
702
}
649
703
704
+ #[ test]
705
+ #[ should_panic( expected = "Error info ptr is null!" ) ]
706
+ fn toggle_with_nullptr_as_error_info_ptr ( ) {
707
+ let game_ptr = create_game ( GameLevel :: Beginner ) ;
708
+ let mut flag_result = FlagResult :: AlreadyOpened ;
709
+ minesweeper_game_toggle_flag ( game_ptr, 0 , 0 , & mut flag_result, std:: ptr:: null_mut ( ) ) ;
710
+ }
711
+
650
712
#[ test]
651
713
fn flag_opened ( ) {
652
714
let mut game_ptr = create_game ( GameLevel :: Beginner ) ;
@@ -692,6 +754,14 @@ mod test {
692
754
destroy_game ( & mut game_ptr) ;
693
755
}
694
756
757
+ #[ test]
758
+ #[ should_panic( expected = "Error info ptr is null!" ) ]
759
+ fn get_width_with_nullptr_as_error_info_ptr ( ) {
760
+ let game_ptr = create_game ( GameLevel :: Beginner ) ;
761
+ let mut width = 0 ;
762
+ minesweeper_game_get_width ( game_ptr, & mut width, std:: ptr:: null_mut ( ) ) ;
763
+ }
764
+
695
765
#[ test]
696
766
fn get_height_with_nullptr_as_game ( ) {
697
767
let mut error_info = create_empty_error_info ( ) ;
@@ -709,6 +779,14 @@ mod test {
709
779
destroy_game ( & mut game_ptr) ;
710
780
}
711
781
782
+ #[ test]
783
+ #[ should_panic( expected = "Error info ptr is null!" ) ]
784
+ fn get_height_with_nullptr_as_error_info_ptr ( ) {
785
+ let game_ptr = create_game ( GameLevel :: Beginner ) ;
786
+ let mut height = 0 ;
787
+ minesweeper_game_get_height ( game_ptr, & mut height, std:: ptr:: null_mut ( ) ) ;
788
+ }
789
+
712
790
#[ test]
713
791
fn get_elapsed_seconds_with_nullptr_as_game ( ) {
714
792
let mut error_info = create_empty_error_info ( ) ;
@@ -725,4 +803,12 @@ mod test {
725
803
assert_eq ! ( CError :: NullPointerAsInput , error_info. error_code) ;
726
804
destroy_game ( & mut game_ptr) ;
727
805
}
806
+
807
+ #[ test]
808
+ #[ should_panic( expected = "Error info ptr is null!" ) ]
809
+ fn get_elapsed_seconds_with_nullptr_as_error_info_ptr ( ) {
810
+ let game_ptr = create_game ( GameLevel :: Beginner ) ;
811
+ let mut elapsed_seconds = 0 ;
812
+ minesweeper_game_get_elapsed_seconds ( game_ptr, & mut elapsed_seconds, std:: ptr:: null_mut ( ) ) ;
813
+ }
728
814
}
0 commit comments