1use crate::{
2 BaseOperations, ControlCommand, DirectBaseOperations, Error, MountOperations, Position, Result,
3 Size, define_command,
4};
5use shared::AnyByLayout;
6
7define_command!(GET_BLOCK_SIZE, Read, b'B', 0, (), u32);
8define_command!(GET_BLOCK_COUNT, Read, b'B', 1, (), u32);
9
10pub trait BlockDevice: BaseOperations + MountOperations {}
11
12pub trait DirectBlockDevice: DirectBaseOperations + MountOperations {
13 fn get_block_size(&self) -> Result<u32> {
14 let mut block_size: u32 = 0;
15
16 self.control(
17 GET_BLOCK_SIZE::IDENTIFIER,
18 AnyByLayout::NONE,
19 AnyByLayout::from_mutable(&mut block_size),
20 )?;
21 Ok(block_size)
22 }
23
24 fn get_block_count(&self) -> Result<Size> {
25 let mut total_size: Size = 0;
26
27 self.control(
28 GET_BLOCK_COUNT::IDENTIFIER,
29 AnyByLayout::NONE,
30 AnyByLayout::from_mutable(&mut total_size),
31 )?;
32 Ok(total_size)
33 }
34}
35
36pub fn set_position(current_position: Size, position: &Position, size: Size) -> Result<Size> {
37 let new_position = match position {
38 Position::Start(position) => (*position)
39 .try_into()
40 .map_err(|_| Error::InvalidParameter)?,
41 Position::Current(offset) => (current_position as i64).wrapping_add(*offset),
42 Position::End(offset) => (size as i64).saturating_add(*offset),
43 };
44
45 if new_position < 0 || (new_position as u64) > size {
46 return Err(Error::InvalidParameter);
47 }
48
49 Ok(new_position as Size)
50}
51
52impl<T> BlockDevice for T where T: DirectBlockDevice + MountOperations {}
53
54pub mod tests {
55 use alloc::vec;
56
57 use crate::{Context, Position};
58
59 use super::*;
60
61 pub fn test_open_and_close<T: BlockDevice>(device: &T) {
63 let mut context = Context::new_empty();
64 device.open(&mut context).unwrap();
65 device.close(&mut context).unwrap();
66 }
67
68 pub fn test_basic_read_write<T: BlockDevice>(device: &T) {
70 let mut context = Context::new_empty();
71
72 let write_data = b"Hello, Context!";
73 let bytes_written = device.write(&mut context, write_data, 0).unwrap();
74 assert_eq!(bytes_written, write_data.len());
75
76 let mut read_buffer = vec![0u8; write_data.len()];
77 let bytes_read = device.read(&mut context, &mut read_buffer, 0).unwrap();
78 assert_eq!(bytes_read, write_data.len());
79 assert_eq!(&read_buffer[..], write_data);
80 }
81
82 pub fn test_write_at_offset<T: BlockDevice>(device: &T) {
84 let mut context = Context::new_empty();
85
86 let data = b"Xila";
87 let offset = 100;
88 let bytes_written = device.write(&mut context, data, offset).unwrap();
89 assert_eq!(bytes_written, data.len());
90
91 let mut read_buffer = vec![0u8; data.len()];
92 let bytes_read = device.read(&mut context, &mut read_buffer, offset).unwrap();
93 assert_eq!(bytes_read, data.len());
94 assert_eq!(&read_buffer[..], data);
95 }
96
97 pub fn test_position_management<T: BlockDevice>(device: &T) {
99 let mut context = Context::new_empty();
100
101 let position = 80;
102
103 let position = device
104 .set_position(&mut context, position, &Position::Start(50))
105 .unwrap();
106 assert_eq!(position, 50);
107
108 let position = device
109 .set_position(&mut context, position, &Position::Current(25))
110 .unwrap();
111 assert_eq!(position, 75);
112 }
113
114 pub fn test_write_pattern<T: BlockDevice>(device: &T) {
116 let mut context = Context::new_empty();
117
118 let pattern = b"XY";
119 let pattern_count = 4;
120 let position = 200;
121 let bytes_written = device
122 .write_pattern(&mut context, pattern, pattern_count, position)
123 .unwrap();
124 assert_eq!(bytes_written, pattern.len() * pattern_count);
125
126 let mut read_buffer = vec![0u8; pattern.len() * pattern_count];
127 let bytes_read = device
128 .read(&mut context, &mut read_buffer, position)
129 .unwrap();
130 assert_eq!(bytes_read, pattern.len() * pattern_count);
131 assert_eq!(&read_buffer[..], b"XYXYXYXY");
132 }
133
134 pub fn test_write_vectored<T: BlockDevice>(device: &T) {
136 let mut context = Context::new_empty();
137
138 let buffers = [b"Alpha".as_slice(), b"Beta".as_slice()];
139 let position = 300;
140 let total_written = device
141 .write_vectored(&mut context, &buffers, position)
142 .unwrap();
143 assert_eq!(total_written, 9); let mut read_buffer = vec![0u8; 9];
146 let bytes_read = device
147 .read(&mut context, &mut read_buffer, position)
148 .unwrap();
149 assert_eq!(bytes_read, 9);
150 assert_eq!(&read_buffer[..], b"AlphaBeta");
151 }
152
153 pub fn test_read_until_delimiter<T: BlockDevice>(device: &T) {
155 let mut context = Context::new_empty();
156
157 let test_data = b"Start|Middle|End";
158 device.write(&mut context, test_data, 400).unwrap();
159
160 let mut read_buffer = vec![0u8; 20];
161 let bytes_read = device
162 .read_until(&mut context, &mut read_buffer, 400, b"|")
163 .unwrap();
164 assert_eq!(&read_buffer[..bytes_read], b"Start|");
165 }
166
167 pub fn test_flush<T: BlockDevice>(device: &T) {
169 let mut context = Context::new_empty();
170 device.flush(&mut context).unwrap();
171 }
172
173 pub fn test_clone_context<T: BlockDevice>(device: &T) {
175 let context = Context::new_empty();
176 let cloned_context = device.clone_context(&context).unwrap();
177 drop(cloned_context);
178 }
179
180 pub fn test_control_commands<T: BlockDevice>(device: &T) {
182 let mut context = Context::new_empty();
183 let mut block_count: Size = 0;
184 device
185 .control(
186 &mut context,
187 GET_BLOCK_COUNT::IDENTIFIER,
188 AnyByLayout::NONE,
189 AnyByLayout::from_mutable(&mut block_count),
190 )
191 .unwrap();
192
193 assert!(block_count > 0);
194
195 let mut block_size: usize = 0;
196 device
197 .control(
198 &mut context,
199 GET_BLOCK_SIZE::IDENTIFIER,
200 AnyByLayout::NONE,
201 AnyByLayout::from_mutable(&mut block_size),
202 )
203 .unwrap();
204
205 assert!(block_size > 0);
206 }
207
208 pub fn test_read_until_boundary_conditions<T: BlockDevice>(device: &T) {
210 let mut context = Context::new_empty();
211
212 let test_data = b"NoDelimiterHere";
214 device.write(&mut context, test_data, 0).unwrap();
215
216 let mut read_buffer = vec![0u8; test_data.len()];
217 let bytes_read = device
218 .read_until(&mut context, &mut read_buffer, 0, b"|")
219 .unwrap();
220 assert_eq!(bytes_read, test_data.len());
221 assert_eq!(&read_buffer[..], test_data);
222
223 let test_data = b"|Start";
225 device.write(&mut context, test_data, 100).unwrap();
226
227 let mut read_buffer = vec![0u8; 10];
228 let bytes_read = device
229 .read_until(&mut context, &mut read_buffer, 100, b"|")
230 .unwrap();
231 assert_eq!(&read_buffer[..bytes_read], b"|");
232
233 let test_data = b"ABACD";
235 device.write(&mut context, test_data, 200).unwrap();
236
237 let mut read_buffer = vec![0u8; test_data.len()];
238 let bytes_read = device
239 .read_until(&mut context, &mut read_buffer, 200, b"ABC")
240 .unwrap();
241 assert_eq!(bytes_read, test_data.len());
242 assert_eq!(&read_buffer[..], test_data);
243 }
244
245 pub fn test_write_pattern_edge_cases<T: BlockDevice>(device: &T) {
247 let mut context = Context::new_empty();
248
249 let pattern = b"XYZ";
251 let bytes_written = device.write_pattern(&mut context, pattern, 0, 0).unwrap();
252 assert_eq!(bytes_written, 0);
253
254 let pattern = b"A";
256 let bytes_written = device.write_pattern(&mut context, pattern, 10, 0).unwrap();
257 assert_eq!(bytes_written, 10);
258
259 let mut read_buffer = vec![0u8; 10];
260 device.read(&mut context, &mut read_buffer, 0).unwrap();
261 assert_eq!(&read_buffer[..], b"AAAAAAAAAA");
262 }
263
264 pub fn test_write_vectored_edge_cases<T: BlockDevice>(device: &T) {
266 let mut context = Context::new_empty();
267
268 let buffers: [&[u8]; 0] = [];
270 let bytes_written = device.write_vectored(&mut context, &buffers, 0).unwrap();
271 assert_eq!(bytes_written, 0);
272
273 let buffers = [b"First".as_slice(), b"".as_slice(), b"Third".as_slice()];
275 let bytes_written = device.write_vectored(&mut context, &buffers, 0).unwrap();
276 assert_eq!(bytes_written, buffers.into_iter().map(|b| b.len()).sum());
277
278 let mut read_buffer = vec![0u8; 10];
279 device.read(&mut context, &mut read_buffer, 0).unwrap();
280 assert_eq!(&read_buffer[..], b"FirstThird");
281 }
282
283 pub fn test_position_wraparound<T: BlockDevice>(device: &T, device_size: Size) {
285 let mut context = Context::new_empty();
286
287 let position = 0;
288 let near_end = device_size.saturating_sub(100);
290 let position = device
291 .set_position(&mut context, position, &Position::Start(near_end))
292 .unwrap();
293 assert_eq!(position, near_end);
294
295 let position = device
297 .set_position(&mut context, position, &Position::Current(50))
298 .unwrap();
299 assert_eq!(position, near_end + 50);
300
301 let position = device
303 .set_position(&mut context, position, &Position::Current(-100))
304 .unwrap();
305 assert_eq!(position, near_end.saturating_sub(50));
306
307 let position = device
309 .set_position(&mut context, position, &Position::End(-50))
310 .unwrap();
311 assert_eq!(position, device_size - 50);
312
313 let position = device
315 .set_position(&mut context, position, &Position::End(0))
316 .unwrap();
317 assert_eq!(position, device_size);
318 }
319
320 pub fn test_concurrent_operations<T: BlockDevice + Sync>(device: &T) {
322 let mut context = Context::new_empty();
323 let mut context_clone = Context::new_empty();
324
325 let write_data = b"Concurrent Write Test";
327 device.write(&mut context, write_data, 0).unwrap();
328
329 let mut read_buffer = vec![0u8; write_data.len()];
331 device
332 .read(&mut context_clone, &mut read_buffer, 0)
333 .unwrap();
334 assert_eq!(&read_buffer[..], write_data);
335 }
336
337 pub fn test_large_read_write<T: BlockDevice>(device: &T) {
339 let mut context = Context::new_empty();
340
341 let large_data = vec![0x42u8; 4096];
343 let bytes_written = device.write(&mut context, &large_data, 0).unwrap();
344 assert_eq!(bytes_written, large_data.len());
345
346 let mut read_buffer = vec![0u8; 4096];
347 let bytes_read = device.read(&mut context, &mut read_buffer, 0).unwrap();
348 assert_eq!(bytes_read, large_data.len());
349 assert_eq!(read_buffer, large_data);
350 }
351
352 #[cfg(test)]
354 mod set_position_tests {
355 use super::*;
356
357 #[test]
358 fn test_position_start_valid() {
359 let result = set_position(100, &Position::Start(50), 1000);
360 assert_eq!(result.unwrap(), 50);
361 }
362
363 #[test]
364 fn test_position_start_at_zero() {
365 let result = set_position(100, &Position::Start(0), 1000);
366 assert_eq!(result.unwrap(), 0);
367 }
368
369 #[test]
370 fn test_position_start_at_size() {
371 let result = set_position(100, &Position::Start(1000), 1000);
372 assert_eq!(result.unwrap(), 1000);
373 }
374
375 #[test]
376 fn test_position_start_exceeds_size() {
377 let result = set_position(100, &Position::Start(1001), 1000);
378 assert!(result.is_err());
379 assert_eq!(result.unwrap_err(), Error::InvalidParameter);
380 }
381
382 #[test]
383 fn test_position_current_positive_offset() {
384 let result = set_position(100, &Position::Current(50), 1000);
385 assert_eq!(result.unwrap(), 150);
386 }
387
388 #[test]
389 fn test_position_current_negative_offset() {
390 let result = set_position(100, &Position::Current(-50), 1000);
391 assert_eq!(result.unwrap(), 50);
392 }
393
394 #[test]
395 fn test_position_current_zero_offset() {
396 let result = set_position(100, &Position::Current(0), 1000);
397 assert_eq!(result.unwrap(), 100);
398 }
399
400 #[test]
401 fn test_position_current_exceeds_size() {
402 let result = set_position(100, &Position::Current(901), 1000);
403 assert!(result.is_err());
404 assert_eq!(result.unwrap_err(), Error::InvalidParameter);
405 }
406
407 #[test]
408 fn test_position_current_wraps_to_valid() {
409 let result = set_position(Size::MAX - 50, &Position::Current(100), Size::MAX);
411 assert_eq!(result.unwrap(), Size::MAX.wrapping_add(50));
412 }
413
414 #[test]
415 fn test_position_end_zero_offset() {
416 let result = set_position(100, &Position::End(0), 1000);
417 assert_eq!(result.unwrap(), 1000);
418 }
419
420 #[test]
421 fn test_position_end_negative_offset() {
422 let result = set_position(100, &Position::End(-50), 1000);
423 assert_eq!(result.unwrap(), 950);
424 }
425
426 #[test]
427 fn test_position_end_positive_offset() {
428 let result = set_position(100, &Position::End(10), 1000);
429 assert!(result.is_err());
430 assert_eq!(result.unwrap_err(), Error::InvalidParameter);
431 }
432
433 #[test]
434 fn test_position_end_negative_exceeds_zero() {
435 let result = set_position(100, &Position::End(-1001), 1000);
436 assert!(result.is_err());
437 assert_eq!(result.unwrap_err(), Error::InvalidParameter);
438 }
439
440 #[test]
441 fn test_position_end_exactly_at_start() {
442 let result = set_position(100, &Position::End(-1000), 1000);
443 assert_eq!(result.unwrap(), 0);
444 }
445
446 #[test]
447 fn test_position_boundaries() {
448 let size = 1000;
450
451 assert_eq!(set_position(0, &Position::Start(0), size).unwrap(), 0);
453 assert_eq!(set_position(0, &Position::Start(size), size).unwrap(), size);
454
455 assert_eq!(set_position(0, &Position::End(0), size).unwrap(), size);
457 assert_eq!(
458 set_position(0, &Position::End(-(size as i64)), size).unwrap(),
459 0
460 );
461
462 assert_eq!(set_position(0, &Position::Current(0), size).unwrap(), 0);
464 assert_eq!(
465 set_position(0, &Position::Current(size as i64), size).unwrap(),
466 size
467 );
468 }
469 }
470
471 #[macro_export]
472 macro_rules! implement_block_device_tests {
473 ($device:expr) => {
474 #[test]
475 fn test_open_close() {
476 let device = $device;
477 $crate::block_device::tests::test_open_and_close(&device);
478 }
479
480 #[test]
481 fn test_basic_read_write() {
482 let device = $device;
483 $crate::block_device::tests::test_basic_read_write(&device);
484 }
485
486 #[test]
487 fn test_write_at_offset() {
488 let device = $device;
489 $crate::block_device::tests::test_write_at_offset(&device);
490 }
491
492 #[test]
493 fn test_position_management() {
494 let device = $device;
495 $crate::block_device::tests::test_position_management(&device);
496 }
497
498 #[test]
499 fn test_write_pattern() {
500 let device = $device;
501 $crate::block_device::tests::test_write_pattern(&device);
502 }
503
504 #[test]
505 fn test_write_vectored() {
506 let device = $device;
507 $crate::block_device::tests::test_write_vectored(&device);
508 }
509
510 #[test]
511 fn test_read_until_delimiter() {
512 let device = $device;
513 $crate::block_device::tests::test_read_until_delimiter(&device);
514 }
515
516 #[test]
517 fn test_flush() {
518 let device = $device;
519 $crate::block_device::tests::test_flush(&device);
520 }
521
522 #[test]
523 fn test_clone_context() {
524 let device = $device;
525 $crate::block_device::tests::test_clone_context(&device);
526 }
527
528 #[test]
529 fn test_control_commands() {
530 let device = $device;
531 $crate::block_device::tests::test_control_commands(&device);
532 }
533
534 #[test]
535 fn test_read_until_boundary_conditions() {
536 let device = $device;
537 $crate::block_device::tests::test_read_until_boundary_conditions(&device);
538 }
539
540 #[test]
541 fn test_write_pattern_edge_cases() {
542 let device = $device;
543 $crate::block_device::tests::test_write_pattern_edge_cases(&device);
544 }
545
546 #[test]
547 fn test_write_vectored_edge_cases() {
548 let device = $device;
549 $crate::block_device::tests::test_write_vectored_edge_cases(&device);
550 }
551
552 #[test]
553 fn test_concurrent_operations() {
554 let device = $device;
555 $crate::block_device::tests::test_concurrent_operations(&device);
556 }
557
558 #[test]
559 fn test_large_read_write() {
560 let device = $device;
561 $crate::block_device::tests::test_large_read_write(&device);
562 }
563 };
564 (
565 instance: $device:expr,
566 size: $size:expr
567 ) => {
568 implement!(instance: $device);
569
570 #[test]
571 fn test_position_wraparound() {
572 let device = $device;
573 test_position_wraparound(&device, $size);
574 }
575 };
576 }
577}