@@ -98,6 +98,9 @@ use prelude::{GbaCell, IrqFn};
98
98
99
99
mod macros;
100
100
101
+ #[ cfg( test) ]
102
+ mod test_harness;
103
+
101
104
#[ cfg( feature = "on_gba" ) ]
102
105
mod asm_runtime;
103
106
#[ cfg( feature = "on_gba" ) ]
@@ -143,31 +146,35 @@ impl<const N: usize> Align4<[u8; N]> {
143
146
/// * If the number of bytes isn't a multiple of 4
144
147
#[ inline]
145
148
#[ must_use]
146
- pub fn as_u32_slice ( & self ) -> & [ u32 ] {
147
- assert ! ( self . 0 . len( ) % 4 == 0 ) ;
148
- // Safety: our struct is aligned to 4, so the pointer will already be
149
- // aligned, we only need to check the length
150
- unsafe {
151
- let data: * const u8 = self . 0 . as_ptr ( ) ;
152
- let len: usize = self . 0 . len ( ) ;
153
- core:: slice:: from_raw_parts ( data. cast :: < u32 > ( ) , len / 4 )
154
- }
149
+ pub const fn as_u32_slice ( & self ) -> & [ u32 ] {
150
+ self . as_slice ( )
155
151
}
156
152
157
153
/// Views these bytes as a slice of `u16`
158
154
/// ## Panics
159
155
/// * If the number of bytes isn't a multiple of 2
160
156
#[ inline]
161
157
#[ must_use]
162
- pub fn as_u16_slice ( & self ) -> & [ u16 ] {
163
- assert ! ( self . 0 . len( ) % 2 == 0 ) ;
164
- // Safety: our struct is aligned to 4, so the pointer will already be
165
- // aligned, we only need to check the length
166
- unsafe {
167
- let data: * const u8 = self . 0 . as_ptr ( ) ;
168
- let len: usize = self . 0 . len ( ) ;
169
- core:: slice:: from_raw_parts ( data. cast :: < u16 > ( ) , len / 2 )
158
+ pub const fn as_u16_slice ( & self ) -> & [ u16 ] {
159
+ self . as_slice ( )
160
+ }
161
+
162
+ /// Views these bytes as a slice of `T`
163
+ /// ## Panics
164
+ /// * If the number of bytes isn't a multiple of T
165
+ /// * If the alignment of T isn't 4, 2, or 1
166
+ #[ inline]
167
+ #[ must_use]
168
+ pub const fn as_slice < T : Sized > ( & self ) -> & [ T ] {
169
+ const {
170
+ assert ! ( N % ( size_of:: <T >( ) + ( size_of:: <T >( ) % align_of:: <T >( ) ) ) == 0 ) ;
171
+ assert ! (
172
+ align_of:: <T >( ) == 4 || align_of:: <T >( ) == 2 || align_of:: <T >( ) == 1
173
+ ) ;
170
174
}
175
+ let data: * const u8 = self . 0 . as_ptr ( ) ;
176
+ let len = const { N / size_of :: < T > ( ) } ;
177
+ unsafe { core:: slice:: from_raw_parts ( data. cast :: < T > ( ) , len) }
171
178
}
172
179
}
173
180
@@ -179,121 +186,6 @@ macro_rules! include_aligned_bytes {
179
186
} } ;
180
187
}
181
188
182
- #[ cfg( test) ]
183
- mod test_harness {
184
- use crate :: prelude:: * ;
185
- use crate :: { bios, mem, mgba} ;
186
- use core:: fmt:: Write ;
187
-
188
- #[ panic_handler]
189
- fn panic ( info : & core:: panic:: PanicInfo ) -> ! {
190
- DISPSTAT . write ( DisplayStatus :: new ( ) . with_irq_vblank ( true ) ) ;
191
- BG_PALETTE . index ( 0 ) . write ( Color :: from_rgb ( 25 , 10 , 5 ) ) ;
192
- IE . write ( IrqBits :: VBLANK ) ;
193
- IME . write ( true ) ;
194
- VBlankIntrWait ( ) ;
195
- VBlankIntrWait ( ) ;
196
- VBlankIntrWait ( ) ;
197
-
198
- // the Fatal one kills emulation after one line / 256 bytes
199
- // so emit all the information as Error first
200
- if let Ok ( mut log) =
201
- mgba:: MgbaBufferedLogger :: try_new ( mgba:: MgbaMessageLevel :: Error )
202
- {
203
- writeln ! ( log, "[failed]" ) . ok ( ) ;
204
- write ! ( log, "{}" , info) . ok ( ) ;
205
- }
206
-
207
- if let Ok ( mut log) =
208
- mgba:: MgbaBufferedLogger :: try_new ( mgba:: MgbaMessageLevel :: Fatal )
209
- {
210
- if let Some ( loc) = info. location ( ) {
211
- write ! ( log, "panic at {loc}! see mgba error log for details." ) . ok ( ) ;
212
- } else {
213
- write ! ( log, "panic! see mgba error log for details." ) . ok ( ) ;
214
- }
215
- }
216
-
217
- IE . write ( IrqBits :: new ( ) ) ;
218
- bios:: IntrWait ( true , IrqBits :: new ( ) ) ;
219
- loop { }
220
- }
221
-
222
- pub ( crate ) trait UnitTest {
223
- fn run ( & self ) ;
224
- }
225
-
226
- impl < T : Fn ( ) > UnitTest for T {
227
- fn run ( & self ) {
228
- if let Ok ( mut log) =
229
- mgba:: MgbaBufferedLogger :: try_new ( mgba:: MgbaMessageLevel :: Info )
230
- {
231
- write ! ( log, "{}..." , core:: any:: type_name:: <T >( ) ) . ok ( ) ;
232
- }
233
-
234
- self ( ) ;
235
-
236
- if let Ok ( mut log) =
237
- mgba:: MgbaBufferedLogger :: try_new ( mgba:: MgbaMessageLevel :: Info )
238
- {
239
- writeln ! ( log, "[ok]" ) . ok ( ) ;
240
- }
241
- }
242
- }
243
-
244
- pub ( crate ) fn test_runner ( tests : & [ & dyn UnitTest ] ) {
245
- if let Ok ( mut log) =
246
- mgba:: MgbaBufferedLogger :: try_new ( mgba:: MgbaMessageLevel :: Info )
247
- {
248
- write ! ( log, "Running {} tests" , tests. len( ) ) . ok ( ) ;
249
- }
250
-
251
- for test in tests {
252
- test. run ( ) ;
253
- }
254
- if let Ok ( mut log) =
255
- mgba:: MgbaBufferedLogger :: try_new ( mgba:: MgbaMessageLevel :: Info )
256
- {
257
- write ! ( log, "Tests finished successfully" ) . ok ( ) ;
258
- }
259
- }
260
-
261
- #[ no_mangle]
262
- extern "C" fn main ( ) {
263
- DISPCNT . write ( DisplayControl :: new ( ) . with_video_mode ( VideoMode :: _0) ) ;
264
- BG_PALETTE . index ( 0 ) . write ( Color :: new ( ) ) ;
265
-
266
- crate :: test_main ( ) ;
267
-
268
- BG_PALETTE . index ( 0 ) . write ( Color :: from_rgb ( 5 , 15 , 25 ) ) ;
269
- BG_PALETTE . index ( 1 ) . write ( Color :: new ( ) ) ;
270
- BG0CNT
271
- . write ( BackgroundControl :: new ( ) . with_charblock ( 0 ) . with_screenblock ( 31 ) ) ;
272
- DISPCNT . write (
273
- DisplayControl :: new ( ) . with_video_mode ( VideoMode :: _0) . with_show_bg0 ( true ) ,
274
- ) ;
275
-
276
- // some niceties for people without mgba-test-runner
277
- let tsb = TEXT_SCREENBLOCKS . get_frame ( 31 ) . unwrap ( ) ;
278
- unsafe {
279
- mem:: set_u32x80_unchecked (
280
- tsb. into_block :: < 1024 > ( ) . as_mut_ptr ( ) . cast ( ) ,
281
- 0 ,
282
- 12 ,
283
- ) ;
284
- }
285
- Cga8x8Thick . bitunpack_4bpp ( CHARBLOCK0_4BPP . as_region ( ) , 0 ) ;
286
-
287
- let row = tsb. get_row ( 9 ) . unwrap ( ) . iter ( ) . skip ( 6 ) ;
288
- for ( addr, ch) in row. zip ( b"all tests passed!" ) {
289
- addr. write ( TextEntry :: new ( ) . with_tile ( * ch as u16 ) ) ;
290
- }
291
-
292
- DISPSTAT . write ( DisplayStatus :: new ( ) ) ;
293
- bios:: IntrWait ( true , IrqBits :: new ( ) ) ;
294
- }
295
- }
296
-
297
189
#[ cfg( test) ]
298
190
mod test {
299
191
use super :: Align4 ;
@@ -304,4 +196,34 @@ mod test {
304
196
assert_eq ! ( a. as_u16_slice( ) , & [ 0x100_u16 . to_le( ) , 0x302_u16 . to_le( ) ] ) ;
305
197
assert_eq ! ( a. as_u32_slice( ) , & [ 0x3020100_u32 . to_le( ) ] ) ;
306
198
}
199
+
200
+ #[ test_case]
201
+ fn align4_as_generic ( ) {
202
+ // with padding
203
+ #[ repr( C , align( 4 ) ) ]
204
+ #[ derive( PartialEq , Debug ) ]
205
+ struct FiveByte ( [ u8 ; 5 ] ) ;
206
+
207
+ assert_eq ! (
208
+ Align4 ( * b"hello...world..." ) . as_slice:: <FiveByte >( ) ,
209
+ & [ FiveByte ( * b"hello" ) , FiveByte ( * b"world" ) ]
210
+ ) ;
211
+
212
+ // and without
213
+ #[ repr( C , align( 2 ) ) ]
214
+ #[ derive( PartialEq , Debug ) ]
215
+ struct ThreeHalfWords ( u16 , u16 , u16 ) ;
216
+
217
+ assert_eq ! (
218
+ Align4 ( [
219
+ 0x11u8 , 0x11u8 , 0x22u8 , 0x22u8 , 0x33u8 , 0x33u8 , 0x44u8 , 0x44u8 , 0x55u8 ,
220
+ 0x55u8 , 0x66u8 , 0x66u8
221
+ ] )
222
+ . as_slice:: <ThreeHalfWords >( ) ,
223
+ & [
224
+ ThreeHalfWords ( 0x1111 , 0x2222 , 0x3333 ) ,
225
+ ThreeHalfWords ( 0x4444 , 0x5555 , 0x6666 )
226
+ ]
227
+ ) ;
228
+ }
307
229
}
0 commit comments