@@ -163,6 +163,52 @@ impl<T: MemKind> MemoryRegion<T> {
163163 }
164164 }
165165
166+ /// Punches a hole (`other`) into the region.
167+ ///
168+ /// # Returns
169+ /// * `(None, None)` if `other` fully contains `self`.
170+ /// * `(Some(Left), None)` if `other` overlaps the tail (end) of `self`,
171+ /// or if `other` is strictly after `self` (no overlap).
172+ /// * `(None, Some(Right))` if `other` overlaps the head (start) of `self`,
173+ /// or if `other` is strictly before `self` (no overlap).
174+ /// * `(Some(Left), Some(Right))` if `other` is strictly inside `self`.
175+ pub fn punch_hole ( self , other : Self ) -> ( Option < Self > , Option < Self > ) {
176+ let s_start = self . start_address ( ) ;
177+ let s_end = self . end_address ( ) ;
178+ let o_start = other. start_address ( ) ;
179+ let o_end = other. end_address ( ) ;
180+
181+ // Calculate the "Left" remainder:
182+ // Exists if self starts before other starts.
183+ // The region is [self.start, min(self.end, other.start)).
184+ let left = if s_start < o_start {
185+ let end = core:: cmp:: min ( s_end, o_start) ;
186+ if end > s_start {
187+ Some ( Self :: from_start_end_address ( s_start, end) )
188+ } else {
189+ None
190+ }
191+ } else {
192+ None
193+ } ;
194+
195+ // Calculate the "Right" remainder:
196+ // Exists if self ends after other ends.
197+ // The region is [max(self.start, other.end), self.end).
198+ let right = if s_end > o_end {
199+ let start = core:: cmp:: max ( s_start, o_end) ;
200+ if start < s_end {
201+ Some ( Self :: from_start_end_address ( start, s_end) )
202+ } else {
203+ None
204+ }
205+ } else {
206+ None
207+ } ;
208+
209+ ( left, right)
210+ }
211+
166212 /// Returns `true` if this region fully contains `other`.
167213 pub fn contains ( self , other : Self ) -> bool {
168214 self . start_address ( ) . value ( ) <= other. start_address ( ) . value ( )
@@ -403,10 +449,14 @@ mod tests {
403449 region:: VirtMemoryRegion ,
404450 } ;
405451
452+ fn region ( start : usize , size : usize ) -> PhysMemoryRegion {
453+ PhysMemoryRegion :: new ( PA :: from_value ( start) , size)
454+ }
455+
406456 #[ test]
407457 fn merge_adjacent ( ) {
408- let a = PhysMemoryRegion :: new ( PA :: from_value ( 0x100 ) , 0x10 ) ;
409- let b = PhysMemoryRegion :: new ( PA :: from_value ( 0x110 ) , 0x10 ) ;
458+ let a = region ( 0x100 , 0x10 ) ;
459+ let b = region ( 0x110 , 0x10 ) ;
410460 let merged = a. merge ( b) . unwrap ( ) ;
411461
412462 assert_eq ! ( merged. address. value( ) , 0x100 ) ;
@@ -415,8 +465,8 @@ mod tests {
415465
416466 #[ test]
417467 fn merge_overlap ( ) {
418- let a = PhysMemoryRegion :: new ( PA :: from_value ( 0x100 ) , 0x20 ) ;
419- let b = PhysMemoryRegion :: new ( PA :: from_value ( 0x110 ) , 0x20 ) ;
468+ let a = region ( 0x100 , 0x20 ) ;
469+ let b = region ( 0x110 , 0x20 ) ;
420470 let merged = a. merge ( b) . unwrap ( ) ;
421471
422472 assert_eq ! ( merged. address. value( ) , 0x100 ) ;
@@ -425,8 +475,8 @@ mod tests {
425475
426476 #[ test]
427477 fn merge_identical ( ) {
428- let a = PhysMemoryRegion :: new ( PA :: from_value ( 0x100 ) , 0x20 ) ;
429- let b = PhysMemoryRegion :: new ( PA :: from_value ( 0x100 ) , 0x20 ) ;
478+ let a = region ( 0x100 , 0x20 ) ;
479+ let b = region ( 0x100 , 0x20 ) ;
430480 let merged = a. merge ( b) . unwrap ( ) ;
431481
432482 assert_eq ! ( merged. address. value( ) , 0x100 ) ;
@@ -435,15 +485,15 @@ mod tests {
435485
436486 #[ test]
437487 fn merge_non_touching ( ) {
438- let a = PhysMemoryRegion :: new ( PA :: from_value ( 0x100 ) , 0x10 ) ;
439- let b = PhysMemoryRegion :: new ( PA :: from_value ( 0x200 ) , 0x10 ) ;
488+ let a = region ( 0x100 , 0x10 ) ;
489+ let b = region ( 0x200 , 0x10 ) ;
440490 assert ! ( a. merge( b) . is_none( ) ) ;
441491 }
442492
443493 #[ test]
444494 fn merge_reverse_order ( ) {
445- let a = PhysMemoryRegion :: new ( PA :: from_value ( 0x200 ) , 0x20 ) ;
446- let b = PhysMemoryRegion :: new ( PA :: from_value ( 0x100 ) , 0x100 ) ;
495+ let a = region ( 0x200 , 0x20 ) ;
496+ let b = region ( 0x100 , 0x100 ) ;
447497 let merged = a. merge ( b) . unwrap ( ) ;
448498
449499 assert_eq ! ( merged. address. value( ) , 0x100 ) ;
@@ -452,8 +502,8 @@ mod tests {
452502
453503 #[ test]
454504 fn merge_partial_overlap ( ) {
455- let a = PhysMemoryRegion :: new ( PA :: from_value ( 0x100 ) , 0x30 ) ; // [0x100, 0x130)
456- let b = PhysMemoryRegion :: new ( PA :: from_value ( 0x120 ) , 0x20 ) ; // [0x120, 0x140)
505+ let a = region ( 0x100 , 0x30 ) ; // [0x100, 0x130)
506+ let b = region ( 0x120 , 0x20 ) ; // [0x120, 0x140)
457507 let merged = a. merge ( b) . unwrap ( ) ; // should be [0x100, 0x140)
458508
459509 assert_eq ! ( merged. address. value( ) , 0x100 ) ;
@@ -462,15 +512,15 @@ mod tests {
462512
463513 #[ test]
464514 fn test_contains_region ( ) {
465- let a = PhysMemoryRegion :: new ( PA :: from_value ( 0x1000 ) , 0x300 ) ;
466- let b = PhysMemoryRegion :: new ( PA :: from_value ( 0x1100 ) , 0x100 ) ;
515+ let a = region ( 0x1000 , 0x300 ) ;
516+ let b = region ( 0x1100 , 0x100 ) ;
467517 assert ! ( a. contains( b) ) ;
468518 assert ! ( !b. contains( a) ) ;
469519 }
470520
471521 #[ test]
472522 fn test_contains_address ( ) {
473- let region = PhysMemoryRegion :: new ( PA :: from_value ( 0x1000 ) , 0x100 ) ;
523+ let region = region ( 0x1000 , 0x100 ) ;
474524 assert ! ( region. contains_address( PA :: from_value( 0x1000 ) ) ) ;
475525 assert ! ( region. contains_address( PA :: from_value( 0x10FF ) ) ) ;
476526 assert ! ( !region. contains_address( PA :: from_value( 0x1100 ) ) ) ;
@@ -534,4 +584,112 @@ mod tests {
534584
535585 assert_eq ! ( region. iter_pages( ) . count( ) , num_pages) ;
536586 }
587+
588+ #[ test]
589+ fn test_punch_hole_middle ( ) {
590+ // Region: [0x1000 ... 0x5000) (size 0x4000)
591+ // Hole: [0x2000 ... 0x3000)
592+ // Expect: Left [0x1000, 0x2000), Right [0x3000, 0x5000)
593+ let main = region ( 0x1000 , 0x4000 ) ;
594+ let hole = region ( 0x2000 , 0x1000 ) ;
595+
596+ let ( left, right) = main. punch_hole ( hole) ;
597+
598+ assert_eq ! ( left, Some ( region( 0x1000 , 0x1000 ) ) ) ;
599+ assert_eq ! ( right, Some ( region( 0x3000 , 0x2000 ) ) ) ;
600+ }
601+
602+ #[ test]
603+ fn test_punch_hole_consumes_start ( ) {
604+ // Region: [0x2000 ... 0x4000)
605+ // Hole: [0x1000 ... 0x3000) (Overlaps the beginning)
606+ // Expect: Left None, Right [0x3000, 0x4000)
607+ let main = region ( 0x2000 , 0x2000 ) ;
608+ let hole = region ( 0x1000 , 0x2000 ) ;
609+
610+ let ( left, right) = main. punch_hole ( hole) ;
611+
612+ assert_eq ! ( left, None ) ;
613+ assert_eq ! ( right, Some ( region( 0x3000 , 0x1000 ) ) ) ;
614+ }
615+
616+ #[ test]
617+ fn test_punch_hole_consumes_end ( ) {
618+ // Region: [0x1000 ... 0x3000)
619+ // Hole: [0x2000 ... 0x4000) (Overlaps the end)
620+ // Expect: Left [0x1000, 0x2000), Right None
621+ let main = region ( 0x1000 , 0x2000 ) ;
622+ let hole = region ( 0x2000 , 0x2000 ) ;
623+
624+ let ( left, right) = main. punch_hole ( hole) ;
625+
626+ assert_eq ! ( left, Some ( region( 0x1000 , 0x1000 ) ) ) ;
627+ assert_eq ! ( right, None ) ;
628+ }
629+
630+ #[ test]
631+ fn test_punch_hole_exact_match ( ) {
632+ // Region: [0x1000 ... 0x2000)
633+ // Hole: [0x1000 ... 0x2000)
634+ // Expect: None, None
635+ let main = region ( 0x1000 , 0x1000 ) ;
636+ let hole = region ( 0x1000 , 0x1000 ) ;
637+
638+ let ( left, right) = main. punch_hole ( hole) ;
639+
640+ assert_eq ! ( left, None ) ;
641+ assert_eq ! ( right, None ) ;
642+ }
643+
644+ #[ test]
645+ fn test_punch_hole_fully_contained ( ) {
646+ // Region: [0x2000 ... 0x3000)
647+ // Hole: [0x1000 ... 0x4000) (Swallows the region entirely)
648+ // Expect: None, None
649+ let main = region ( 0x2000 , 0x1000 ) ;
650+ let hole = region ( 0x1000 , 0x3000 ) ;
651+
652+ let ( left, right) = main. punch_hole ( hole) ;
653+
654+ assert_eq ! ( left, None ) ;
655+ assert_eq ! ( right, None ) ;
656+ }
657+
658+ #[ test]
659+ fn test_punch_hole_touching_edges ( ) {
660+ // Case A: Hole ends exactly where region starts
661+ // Region: [0x2000 ... 0x3000)
662+ // Hole: [0x1000 ... 0x2000)
663+ // Result: Region is to the right of the hole.
664+ let main = region ( 0x2000 , 0x1000 ) ;
665+ let hole = region ( 0x1000 , 0x1000 ) ;
666+ assert_eq ! ( main. punch_hole( hole) , ( None , Some ( main) ) ) ;
667+
668+ // Case B: Hole starts exactly where region ends
669+ // Region: [0x1000 ... 0x2000)
670+ // Hole: [0x2000 ... 0x3000)
671+ // Result: Region is to the left of the hole.
672+ let main = region ( 0x1000 , 0x1000 ) ;
673+ let hole = region ( 0x2000 , 0x1000 ) ;
674+ assert_eq ! ( main. punch_hole( hole) , ( Some ( main) , None ) ) ;
675+ }
676+
677+ #[ test]
678+ fn test_punch_hole_disjoint ( ) {
679+ // Hole is completely far away (after)
680+ // Region: [0x1000 ... 0x2000)
681+ // Hole: [0x5000 ... 0x6000)
682+ // Result: Region is to the left of the hole.
683+ let main = region ( 0x1000 , 0x1000 ) ;
684+ let hole = region ( 0x5000 , 0x1000 ) ;
685+ assert_eq ! ( main. punch_hole( hole) , ( Some ( main) , None ) ) ;
686+
687+ // Hole is completely far away (before)
688+ // Region: [0x5000 ... 0x6000)
689+ // Hole: [0x1000 ... 0x2000)
690+ // Result: Region is to the right of the hole.
691+ let main = region ( 0x5000 , 0x1000 ) ;
692+ let hole = region ( 0x1000 , 0x1000 ) ;
693+ assert_eq ! ( main. punch_hole( hole) , ( None , Some ( main) ) ) ;
694+ }
537695}
0 commit comments