Skip to content

Commit f7db6a8

Browse files
Daniel-Aaron-Bloomjiangliu
authored andcommitted
Add an iterator interface to the GuestMemory trait
Signed-off-by: Daniel Bloom <[email protected]>
1 parent be14339 commit f7db6a8

File tree

4 files changed

+102
-41
lines changed

4 files changed

+102
-41
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [Unreleased]
4+
5+
### Added
6+
7+
- [[#8]](https://github.com/rust-vmm/vm-memory/issues/8): Add GuestMemory method to return an Iterator
8+
39
## [v0.4.0]
410

511
### Fixed

coverage_config_x86_64.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"coverage_score": 85.5,
2+
"coverage_score": 85.6,
33
"exclude_path": "mmap_windows.rs",
44
"crate_features": "backend-mmap,backend-atomic"
55
}

src/guest_memory.rs

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,25 @@ impl<M: GuestMemory> GuestAddressSpace for Arc<M> {
394394
}
395395
}
396396

397+
/// Lifetime generic associated iterators. The actual iterator type is defined through associated
398+
/// item `Iter`, for example:
399+
///
400+
/// ```ignore
401+
/// impl<'a> GuestMemoryIterator<'a, MyGuestRegion> for MyGuestMemory {
402+
/// type Iter = MyGuestMemoryIter<'a>;
403+
/// }
404+
///
405+
/// pub struct MyGuestMemoryIter<`a>( /* ... */ );
406+
/// impl<'a> Iterator for MyGuestMemoryIter<'a> {
407+
/// type Item = &'a MyGuestRegion;
408+
/// /* ... */
409+
/// }
410+
/// ```
411+
pub trait GuestMemoryIterator<'a, R: 'a> {
412+
/// Type of the `iter` method's return value.
413+
type Iter: Iterator<Item = &'a R>;
414+
}
415+
397416
/// `GuestMemory` represents a container for an *immutable* collection of
398417
/// `GuestMemoryRegion` objects. `GuestMemory` provides the `Bytes<GuestAddress>`
399418
/// trait to hide the details of accessing guest memory by physical address.
@@ -407,6 +426,9 @@ pub trait GuestMemory {
407426
/// Type of objects hosted by the address space.
408427
type R: GuestMemoryRegion;
409428

429+
/// Lifetime generic associated iterators. Usually this is just `Self`.
430+
type I: for<'a> GuestMemoryIterator<'a, Self::R>;
431+
410432
/// Returns the number of regions in the collection.
411433
fn num_regions(&self) -> usize;
412434

@@ -418,14 +440,55 @@ pub trait GuestMemory {
418440
/// It only walks children of current region and does not step into sub regions.
419441
fn with_regions<F, E>(&self, cb: F) -> std::result::Result<(), E>
420442
where
421-
F: Fn(usize, &Self::R) -> std::result::Result<(), E>;
443+
F: Fn(usize, &Self::R) -> std::result::Result<(), E>,
444+
{
445+
for (index, region) in self.iter().enumerate() {
446+
cb(index, region)?;
447+
}
448+
Ok(())
449+
}
422450

423451
/// Perform the specified action on each region mutably.
424452
///
425453
/// It only walks children of current region and does not step into sub regions.
426-
fn with_regions_mut<F, E>(&self, cb: F) -> std::result::Result<(), E>
454+
fn with_regions_mut<F, E>(&self, mut cb: F) -> std::result::Result<(), E>
427455
where
428-
F: FnMut(usize, &Self::R) -> std::result::Result<(), E>;
456+
F: FnMut(usize, &Self::R) -> std::result::Result<(), E>,
457+
{
458+
for (index, region) in self.iter().enumerate() {
459+
cb(index, region)?;
460+
}
461+
Ok(())
462+
}
463+
464+
/// Gets an iterator over the entries in the collection.
465+
///
466+
/// # Examples
467+
///
468+
/// * Compute the total size of all memory mappings in KB by iterating over the memory regions
469+
/// and dividing their sizes to 1024, then summing up the values in an accumulator.
470+
///
471+
/// ```
472+
/// # #[cfg(feature = "backend-mmap")]
473+
/// # use vm_memory::{GuestAddress, GuestMemory, GuestMemoryRegion, GuestMemoryMmap};
474+
///
475+
/// # #[cfg(feature = "backend-mmap")]
476+
/// # fn test_map_fold() -> Result<(), ()> {
477+
/// let start_addr1 = GuestAddress(0x0);
478+
/// let start_addr2 = GuestAddress(0x400);
479+
/// let mem = GuestMemoryMmap::from_ranges(&vec![(start_addr1, 1024), (start_addr2, 2048)])
480+
/// .unwrap();
481+
/// let total_size = mem.iter()
482+
/// .map(|region| region.len() / 1024)
483+
/// .fold(0, |acc, size| acc + size);
484+
/// println!("Total memory size = {} KB", total_size);
485+
/// Ok(())
486+
/// # }
487+
///
488+
/// # #[cfg(feature = "backend-mmap")]
489+
/// # test_map_fold();
490+
/// ```
491+
fn iter(&self) -> <Self::I as GuestMemoryIterator<Self::R>>::Iter;
429492

430493
/// Applies two functions, specified as callbacks, on the inner memory regions.
431494
///
@@ -468,7 +531,10 @@ pub trait GuestMemory {
468531
fn map_and_fold<F, G, T>(&self, init: T, mapf: F, foldf: G) -> T
469532
where
470533
F: Fn((usize, &Self::R)) -> T,
471-
G: Fn(T, T) -> T;
534+
G: Fn(T, T) -> T,
535+
{
536+
self.iter().enumerate().map(mapf).fold(init, foldf)
537+
}
472538

473539
/// Returns the maximum (inclusive) address managed by the
474540
/// [`GuestMemory`](trait.GuestMemory.html).
@@ -491,11 +557,9 @@ pub trait GuestMemory {
491557
/// # test_last_addr();
492558
/// ```
493559
fn last_addr(&self) -> GuestAddress {
494-
self.map_and_fold(
495-
GuestAddress(0),
496-
|(_, region)| region.last_addr(),
497-
std::cmp::max,
498-
)
560+
self.iter()
561+
.map(GuestMemoryRegion::last_addr)
562+
.fold(GuestAddress(0), std::cmp::max)
499563
}
500564

501565
/// Tries to convert an absolute address to a relative address within the corresponding region.

src/mmap.rs

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ use std::sync::Arc;
2323

2424
use crate::address::Address;
2525
use crate::guest_memory::{
26-
self, FileOffset, GuestAddress, GuestMemory, GuestMemoryRegion, GuestUsize, MemoryRegionAddress,
26+
self, FileOffset, GuestAddress, GuestMemory, GuestMemoryIterator, GuestMemoryRegion,
27+
GuestUsize, MemoryRegionAddress,
2728
};
2829
use crate::volatile_memory::{VolatileMemory, VolatileSlice};
2930
use crate::{AtomicAccess, Bytes};
@@ -539,9 +540,27 @@ impl GuestMemoryMmap {
539540
}
540541
}
541542

543+
/// An iterator over the elements of `GuestMemoryMmap`.
544+
///
545+
/// This struct is created by `GuestMemory::iter()`. See its documentation for more.
546+
pub struct Iter<'a>(std::slice::Iter<'a, Arc<GuestRegionMmap>>);
547+
548+
impl<'a> Iterator for Iter<'a> {
549+
type Item = &'a GuestRegionMmap;
550+
fn next(&mut self) -> Option<Self::Item> {
551+
self.0.next().map(AsRef::as_ref)
552+
}
553+
}
554+
555+
impl<'a> GuestMemoryIterator<'a, GuestRegionMmap> for GuestMemoryMmap {
556+
type Iter = Iter<'a>;
557+
}
558+
542559
impl GuestMemory for GuestMemoryMmap {
543560
type R = GuestRegionMmap;
544561

562+
type I = Self;
563+
545564
fn num_regions(&self) -> usize {
546565
self.regions.len()
547566
}
@@ -556,36 +575,8 @@ impl GuestMemory for GuestMemoryMmap {
556575
index.map(|x| self.regions[x].as_ref())
557576
}
558577

559-
fn with_regions<F, E>(&self, cb: F) -> result::Result<(), E>
560-
where
561-
F: Fn(usize, &Self::R) -> result::Result<(), E>,
562-
{
563-
for (index, region) in self.regions.iter().enumerate() {
564-
cb(index, region)?;
565-
}
566-
Ok(())
567-
}
568-
569-
fn with_regions_mut<F, E>(&self, mut cb: F) -> result::Result<(), E>
570-
where
571-
F: FnMut(usize, &Self::R) -> result::Result<(), E>,
572-
{
573-
for (index, region) in self.regions.iter().enumerate() {
574-
cb(index, region)?;
575-
}
576-
Ok(())
577-
}
578-
579-
fn map_and_fold<F, G, T>(&self, init: T, mapf: F, foldf: G) -> T
580-
where
581-
F: Fn((usize, &Self::R)) -> T,
582-
G: Fn(T, T) -> T,
583-
{
584-
self.regions
585-
.iter()
586-
.enumerate()
587-
.map(|(idx, region)| mapf((idx, region.as_ref())))
588-
.fold(init, foldf)
578+
fn iter(&self) -> Iter {
579+
Iter(self.regions.iter())
589580
}
590581
}
591582

0 commit comments

Comments
 (0)