@@ -98,6 +98,9 @@ use prelude::{GbaCell, IrqFn};
9898
9999mod macros;
100100
101+ #[ cfg( test) ]
102+ mod test_harness;
103+
101104#[ cfg( feature = "on_gba" ) ]
102105mod asm_runtime;
103106#[ cfg( feature = "on_gba" ) ]
@@ -143,31 +146,35 @@ impl<const N: usize> Align4<[u8; N]> {
143146 /// * If the number of bytes isn't a multiple of 4
144147 #[ inline]
145148 #[ 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 ( )
155151 }
156152
157153 /// Views these bytes as a slice of `u16`
158154 /// ## Panics
159155 /// * If the number of bytes isn't a multiple of 2
160156 #[ inline]
161157 #[ 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+ ) ;
170174 }
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) }
171178 }
172179}
173180
@@ -179,121 +186,6 @@ macro_rules! include_aligned_bytes {
179186 } } ;
180187}
181188
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-
297189#[ cfg( test) ]
298190mod test {
299191 use super :: Align4 ;
@@ -304,4 +196,34 @@ mod test {
304196 assert_eq ! ( a. as_u16_slice( ) , & [ 0x100_u16 . to_le( ) , 0x302_u16 . to_le( ) ] ) ;
305197 assert_eq ! ( a. as_u32_slice( ) , & [ 0x3020100_u32 . to_le( ) ] ) ;
306198 }
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+ }
307229}
0 commit comments