1use core::fmt;
9
10use crate::{Device, DeviceTrait, Result, Size};
11
12pub struct PartitionDevice {
42 base_device: Device,
44 offset: u64,
46 size: u64,
48 position: core::sync::atomic::AtomicU64,
50}
51
52impl PartitionDevice {
53 pub fn new(base_device: Device, offset: u64, size: u64) -> Self {
72 Self {
73 base_device,
74 offset,
75 size,
76 position: core::sync::atomic::AtomicU64::new(0),
77 }
78 }
79
80 pub fn new_from_lba(base_device: Device, start_lba: u32, sector_count: u32) -> Self {
102 let offset = start_lba as u64 * 512;
103 let size = sector_count as u64 * 512;
104 Self::new(base_device, offset, size)
105 }
106
107 pub fn get_offset(&self) -> u64 {
124 self.offset
125 }
126
127 pub fn get_partition_size(&self) -> u64 {
144 self.size
145 }
146
147 pub fn get_start_lba(&self) -> u32 {
164 (self.offset / 512) as u32
165 }
166
167 pub fn get_sector_count(&self) -> u32 {
184 (self.size / 512) as u32
185 }
186
187 pub fn get_position(&self) -> u64 {
189 self.position.load(core::sync::atomic::Ordering::Relaxed)
190 }
191
192 pub fn get_base_device(&self) -> &Device {
194 &self.base_device
195 }
196
197 pub fn is_valid(&self) -> bool {
199 self.size > 0
200 }
201
202 pub fn get_remaining_bytes(&self) -> u64 {
204 let current_pos = self.get_position();
205 self.size.saturating_sub(current_pos)
206 }
207
208 pub fn is_at_end(&self) -> bool {
210 self.get_position() >= self.size
211 }
212}
213
214impl Clone for PartitionDevice {
215 fn clone(&self) -> Self {
216 Self {
217 base_device: self.base_device.clone(),
218 offset: self.offset,
219 size: self.size,
220 position: core::sync::atomic::AtomicU64::new(0), }
222 }
223}
224
225impl DeviceTrait for PartitionDevice {
226 fn read(&self, buffer: &mut [u8]) -> Result<Size> {
227 let current_pos = self.position.load(core::sync::atomic::Ordering::Relaxed);
228
229 if current_pos >= self.size {
230 return Ok(Size::new(0));
231 }
232
233 let available = (self.size - current_pos).min(buffer.len() as u64);
234 let read_size = available as usize;
235
236 let absolute_pos = self.offset + current_pos;
238 self.base_device
239 .set_position(&crate::Position::Start(absolute_pos))?;
240
241 let bytes_read = self.base_device.read(&mut buffer[..read_size])?;
243
244 self.position.store(
246 current_pos + bytes_read.as_u64(),
247 core::sync::atomic::Ordering::Relaxed,
248 );
249
250 Ok(bytes_read)
251 }
252
253 fn write(&self, buffer: &[u8]) -> Result<Size> {
254 let current_pos = self.position.load(core::sync::atomic::Ordering::Relaxed);
255
256 if current_pos >= self.size {
257 return Ok(Size::new(0));
258 }
259
260 let available = (self.size - current_pos).min(buffer.len() as u64);
261 let write_size = available as usize;
262
263 let absolute_pos = self.offset + current_pos;
265 self.base_device
266 .set_position(&crate::Position::Start(absolute_pos))?;
267
268 let bytes_written = self.base_device.write(&buffer[..write_size])?;
270
271 self.position.store(
273 current_pos + bytes_written.as_u64(),
274 core::sync::atomic::Ordering::Relaxed,
275 );
276
277 Ok(bytes_written)
278 }
279
280 fn get_size(&self) -> Result<Size> {
281 Ok(Size::new(self.size))
282 }
283
284 fn set_position(&self, position: &crate::Position) -> Result<Size> {
285 use crate::Position;
286
287 let new_pos = match position {
288 Position::Start(offset) => *offset,
289 Position::Current(offset) => {
290 let current = self.position.load(core::sync::atomic::Ordering::Relaxed);
291 if *offset >= 0 {
292 current.saturating_add(*offset as u64)
293 } else {
294 current.saturating_sub((-*offset) as u64)
295 }
296 }
297 Position::End(offset) => {
298 if *offset >= 0 {
299 self.size.saturating_add(*offset as u64)
300 } else {
301 self.size.saturating_sub((-*offset) as u64)
302 }
303 }
304 };
305
306 let clamped_pos = new_pos.min(self.size);
307 self.position
308 .store(clamped_pos, core::sync::atomic::Ordering::Relaxed);
309
310 Ok(Size::new(clamped_pos))
311 }
312
313 fn flush(&self) -> Result<()> {
314 self.base_device.flush()
315 }
316
317 fn is_a_block_device(&self) -> bool {
318 self.base_device.is_a_block_device()
319 }
320
321 fn get_block_size(&self) -> Result<usize> {
322 self.base_device.get_block_size()
323 }
324
325 fn is_a_terminal(&self) -> bool {
326 false }
328
329 fn erase(&self) -> Result<()> {
330 self.base_device.erase()
333 }
334}
335
336impl fmt::Debug for PartitionDevice {
337 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
338 formatter
339 .debug_struct("Partition_device_type")
340 .field("offset", &self.offset)
341 .field("size", &self.size)
342 .field("start_lba", &self.get_start_lba())
343 .field("sector_count", &self.get_sector_count())
344 .field("position", &self.get_position())
345 .field("remaining_bytes", &self.get_remaining_bytes())
346 .field("is_valid", &self.is_valid())
347 .finish()
348 }
349}
350
351impl fmt::Display for PartitionDevice {
352 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
353 write!(
354 formatter,
355 "Partition Device: Start LBA={}, Sectors={}, Size={} bytes, Position={}/{}",
356 self.get_start_lba(),
357 self.get_sector_count(),
358 self.size,
359 self.get_position(),
360 self.size
361 )
362 }
363}
364
365#[cfg(test)]
366mod tests {
367 use super::PartitionDevice;
368 use crate::{Device, DeviceTrait, MemoryDevice, Position};
369
370 fn create_test_device() -> Device {
372 let memory_device = MemoryDevice::<512>::new(4096);
373 crate::create_device!(memory_device)
374 }
375
376 #[test]
377 fn test_partition_device_creation() {
378 let base_device = create_test_device();
379 let partition = PartitionDevice::new(base_device, 512, 1024);
380
381 assert_eq!(partition.get_offset(), 512);
382 assert_eq!(partition.get_partition_size(), 1024);
383 assert_eq!(partition.get_position(), 0);
384 assert!(partition.is_valid());
385 }
386
387 #[test]
388 fn test_partition_device_from_lba() {
389 let base_device = create_test_device();
390 let partition = PartitionDevice::new_from_lba(base_device, 4, 8);
391
392 assert_eq!(partition.get_offset(), 4 * 512); assert_eq!(partition.get_partition_size(), 8 * 512); assert_eq!(partition.get_start_lba(), 4);
395 assert_eq!(partition.get_sector_count(), 8);
396 }
397
398 #[test]
399 fn test_partition_device_lba_calculations() {
400 let base_device = create_test_device();
401 let partition = PartitionDevice::new(base_device, 1024, 2048);
402
403 assert_eq!(partition.get_start_lba(), 2); assert_eq!(partition.get_sector_count(), 4); }
406
407 #[test]
408 fn test_partition_device_validity() {
409 let base_device = create_test_device();
410
411 let valid_partition = PartitionDevice::new(base_device.clone(), 0, 1024);
412 assert!(valid_partition.is_valid());
413
414 let invalid_partition = PartitionDevice::new(base_device, 0, 0);
415 assert!(!invalid_partition.is_valid());
416 }
417
418 #[test]
419 fn test_partition_device_remaining_bytes() {
420 let base_device = create_test_device();
421 let partition = PartitionDevice::new(base_device, 0, 1000);
422
423 assert_eq!(partition.get_remaining_bytes(), 1000);
425 assert!(!partition.is_at_end());
426
427 let _ = partition.set_position(&Position::Start(500));
429 assert_eq!(partition.get_remaining_bytes(), 500);
430 assert!(!partition.is_at_end());
431
432 let _ = partition.set_position(&Position::Start(1000));
434 assert_eq!(partition.get_remaining_bytes(), 0);
435 assert!(partition.is_at_end());
436
437 let _ = partition.set_position(&Position::Start(1500));
439 assert_eq!(partition.get_remaining_bytes(), 0);
440 assert!(partition.is_at_end());
441 }
442
443 #[test]
444 fn test_partition_device_position_setting() {
445 let base_device = create_test_device();
446 let partition = PartitionDevice::new(base_device, 0, 1000);
447
448 let result = partition.set_position(&Position::Start(100));
450 assert!(result.is_ok());
451 assert_eq!(result.unwrap().as_u64(), 100);
452 assert_eq!(partition.get_position(), 100);
453
454 let result = partition.set_position(&Position::Current(50));
456 assert!(result.is_ok());
457 assert_eq!(result.unwrap().as_u64(), 150);
458 assert_eq!(partition.get_position(), 150);
459
460 let result = partition.set_position(&Position::Current(-30));
462 assert!(result.is_ok());
463 assert_eq!(result.unwrap().as_u64(), 120);
464 assert_eq!(partition.get_position(), 120);
465
466 let result = partition.set_position(&Position::End(-200));
468 assert!(result.is_ok());
469 assert_eq!(result.unwrap().as_u64(), 800);
470 assert_eq!(partition.get_position(), 800);
471
472 let result = partition.set_position(&Position::End(500));
474 assert!(result.is_ok());
475 assert_eq!(result.unwrap().as_u64(), 1000);
476 assert_eq!(partition.get_position(), 1000);
477
478 let result = partition.set_position(&Position::Start(2000));
480 assert!(result.is_ok());
481 assert_eq!(result.unwrap().as_u64(), 1000);
482 assert_eq!(partition.get_position(), 1000);
483 }
484
485 #[test]
486 fn test_partition_device_get_size() {
487 let base_device = create_test_device();
488 let partition = PartitionDevice::new(base_device, 100, 1500);
489
490 let size_result = partition.get_size();
491 assert!(size_result.is_ok());
492 assert_eq!(size_result.unwrap().as_u64(), 1500);
493 }
494
495 #[test]
496 fn test_partition_device_read() {
497 let base_device = create_test_device();
498 let partition = PartitionDevice::new(base_device, 0, 100);
499
500 let mut buffer = [0u8; 50];
502 let result = partition.read(&mut buffer);
503 assert!(result.is_ok());
504 assert_eq!(result.unwrap().as_u64(), 50);
505 assert_eq!(partition.get_position(), 50);
506
507 let mut buffer = [0u8; 100];
509 let result = partition.read(&mut buffer);
510 assert!(result.is_ok());
511 assert_eq!(result.unwrap().as_u64(), 50); assert_eq!(partition.get_position(), 100);
513
514 let mut buffer = [0u8; 10];
516 let result = partition.read(&mut buffer);
517 assert!(result.is_ok());
518 assert_eq!(result.unwrap().as_u64(), 0); assert_eq!(partition.get_position(), 100);
520 }
521
522 #[test]
523 fn test_partition_device_write() {
524 let base_device = create_test_device();
525 let partition = PartitionDevice::new(base_device, 0, 100);
526
527 let buffer = [0x42u8; 30];
529 let result = partition.write(&buffer);
530 assert!(result.is_ok());
531 assert_eq!(result.unwrap().as_u64(), 30);
532 assert_eq!(partition.get_position(), 30);
533
534 let _ = partition.set_position(&Position::Start(80));
536 let buffer = [0x42u8; 30];
537 let result = partition.write(&buffer);
538 assert!(result.is_ok());
539 assert_eq!(result.unwrap().as_u64(), 20); assert_eq!(partition.get_position(), 100);
541
542 let buffer = [0x42u8; 10];
544 let result = partition.write(&buffer);
545 assert!(result.is_ok());
546 assert_eq!(result.unwrap().as_u64(), 0); assert_eq!(partition.get_position(), 100);
548 }
549
550 #[test]
551 fn test_partition_device_block_operations() {
552 let base_device = create_test_device();
553 let partition = PartitionDevice::new(base_device, 0, 1000);
554
555 let is_block = partition.is_a_block_device();
557 let block_size = partition.get_block_size();
558
559 assert!(!is_block);
562 assert!(block_size.is_ok());
563
564 assert!(!partition.is_a_terminal());
566 }
567
568 #[test]
569 fn test_partition_device_flush_and_erase() {
570 let base_device = create_test_device();
571 let partition = PartitionDevice::new(base_device, 0, 1000);
572
573 let flush_result = partition.flush();
575 assert!(flush_result.is_ok());
576
577 let erase_result = partition.erase();
579 assert!(erase_result.is_ok());
580 }
581
582 #[test]
583 fn test_partition_device_debug_display() {
584 let base_device = create_test_device();
585 let partition = PartitionDevice::new_from_lba(base_device, 10, 20);
586
587 let debug_str = alloc::format!("{partition:?}");
589 assert!(debug_str.contains("Partition_device_type"));
590 assert!(debug_str.contains("offset"));
591 assert!(debug_str.contains("size"));
592 assert!(debug_str.contains("start_lba"));
593
594 let display_str = alloc::format!("{partition}");
596 assert!(display_str.contains("Partition Device"));
597 assert!(display_str.contains("Start LBA=10"));
598 assert!(display_str.contains("Sectors=20"));
599 }
600
601 #[test]
602 fn test_partition_device_edge_cases() {
603 let base_device = create_test_device();
604
605 let partition1 = PartitionDevice::new(base_device.clone(), 0, 512);
607 assert_eq!(partition1.get_start_lba(), 0);
608 assert_eq!(partition1.get_sector_count(), 1);
609
610 let partition2 = PartitionDevice::new(base_device.clone(), 512, 1);
612 assert_eq!(partition2.get_partition_size(), 1);
613 assert!(partition2.is_valid());
614
615 let partition3 = PartitionDevice::new_from_lba(base_device, 0xFFFFFFFF - 1, 1);
617 assert_eq!(partition3.get_start_lba(), 0xFFFFFFFF - 1);
618 assert_eq!(partition3.get_sector_count(), 1);
619 }
620
621 #[test]
622 fn test_partition_device_concurrent_access() {
623 let base_device = create_test_device();
624 let partition = PartitionDevice::new(base_device, 0, 1000);
625
626 let _ = partition.set_position(&Position::Start(100));
628 assert_eq!(partition.get_position(), 100);
629
630 for _ in 0..10 {
632 assert_eq!(partition.get_position(), 100);
633 }
634 }
635
636 #[test]
637 fn test_partition_device_clone() {
638 let base_device = create_test_device();
639 let original = PartitionDevice::new(base_device, 512, 1024);
640 let cloned = original.clone();
641
642 assert_eq!(original.get_offset(), cloned.get_offset());
644 assert_eq!(original.get_partition_size(), cloned.get_partition_size());
645 assert_eq!(original.get_start_lba(), cloned.get_start_lba());
646 assert_eq!(original.get_sector_count(), cloned.get_sector_count());
647
648 let _ = original.set_position(&Position::Start(100));
650 assert_eq!(original.get_position(), 100);
651 assert_eq!(cloned.get_position(), 0); }
653}