99#[ cfg( any( test, feature = "backend-bitmap" ) ) ]
1010mod backend;
1111
12- use std:: fmt:: Debug ;
13-
1412use crate :: { GuestMemory , GuestMemoryRegion } ;
1513
1614#[ cfg( any( test, feature = "backend-bitmap" ) ) ]
1715pub use backend:: { ArcSlice , AtomicBitmap , RefSlice } ;
1816
19- /// Trait implemented by types that support creating `BitmapSlice` objects.
20- pub trait WithBitmapSlice < ' a > {
21- /// Type of the bitmap slice.
22- type S : BitmapSlice ;
17+ /// Trait for things that can be sliced.
18+ ///
19+ /// Slicing can mean two things:
20+ /// 1. You have ownership of a bitmap, and slicing gives you a borrowed version of it (e.g.
21+ /// akin to `Vec<T> -> &'a [T]`)
22+ /// 2. You already have a borrowed version of a bitmap, and want to subslice it.
23+ ///
24+ /// The trouble is that if we encode slicing at the type level, then each time a bitmap gets
25+ /// sliced, we get a new type - the return type of something like `bitmap.slice_at().slice_at()`
26+ /// would be `B::Slice<'a>::Slice<'b>`. Effectively, we're dealing with infinite types, which
27+ /// would make things like `VolatileSlice` that have a `B: Bitmap` parameter impossible to work
28+ /// with. To avoid this, the associated type has such a weird bound: It says that each subsequent
29+ /// slice of a slice must have the same type (including lifetimes) as the first slice. E.g.
30+ /// for all possible lifetimes `'b`, we have `B::Slice<'a>::Slice<'b> == B::Slice<'a>`.
31+ /// This then inductively collapses the type of subsequent `slice_at` calls to just be
32+ /// `B::Slice<'a>`. This simplification is based on the assumption that a function with the
33+ /// signature
34+ ///
35+ /// ```no_run
36+ /// fn slice_at<'a, 'b, B: vm_memory::bitmap::Bitmap>(slice: &'b B::Slice<'a>) -> B::Slice<'a>
37+ /// where
38+ /// 'a: 'b { todo!() }
39+ /// ```
40+ ///
41+ /// can always be written (note the returned value having a lifetime of `'a`, which outlives
42+ /// the lifetime `'b` of the reference passed into the function). Conceptually, this makes sense
43+ /// though: Slicing multiple times will return references to the object originally being sliced,
44+ /// so the lifetime should reflect this tie to the original bitmap being sliced, and not a tie
45+ /// to a slice of the original bitmap.
46+ ///
47+ /// Note: This trait cannot be merged with [`Bitmap`] because of rust-lang#87479 (it would
48+ /// force a `where Self: 'a` bound onto the associated type, which is imposible to satisfy
49+ /// for implementors due to the higher-ranked trait bound).
50+ pub trait Sliceable {
51+ /// The type of the slice we get after calling [`Bitmap::slice_at`].
52+ type Slice < ' a > : BitmapSlice ;
2353}
2454
25- /// Trait used to represent that a `BitmapSlice` is a `Bitmap` itself, but also satisfies the
26- /// restriction that slices created from it have the same type as `Self`.
27- pub trait BitmapSlice : Bitmap + Clone + Debug + for < ' a > WithBitmapSlice < ' a , S = Self > { }
55+ pub trait BitmapSlice : for < ' a > Bitmap < Slice < ' a > = Self > where { }
2856
29- /// Common bitmap operations. Using Higher-Rank Trait Bounds (HRTBs) to effectively define
30- /// an associated type that has a lifetime parameter, without tagging the `Bitmap` trait with
31- /// a lifetime as well .
57+ impl < B > BitmapSlice for B where B : for < ' a > Bitmap < Slice < ' a > = B > { }
58+
59+ /// Common bitmap operations .
3260///
3361/// Using an associated type allows implementing the `Bitmap` and `BitmapSlice` functionality
3462/// as a zero-cost abstraction when providing trivial implementations such as the one
3563/// defined for `()`.
3664// These methods represent the core functionality that's required by `vm-memory` abstractions
3765// to implement generic tracking logic, as well as tests that can be reused by different backends.
38- pub trait Bitmap : for < ' a > WithBitmapSlice < ' a > {
66+ pub trait Bitmap : Sliceable + Clone {
3967 /// Mark the memory range specified by the given `offset` and `len` as dirtied.
4068 fn mark_dirty ( & self , offset : usize , len : usize ) ;
4169
4270 /// Check whether the specified `offset` is marked as dirty.
4371 fn dirty_at ( & self , offset : usize ) -> bool ;
4472
45- /// Return a `<Self as WithBitmapSlice>::S ` slice of the current bitmap, starting at
73+ /// Return a `BitmapSlice ` slice of the current bitmap, starting at
4674 /// the specified `offset`.
47- fn slice_at ( & self , offset : usize ) -> < Self as WithBitmapSlice > :: S ;
75+ fn slice_at ( & self , offset : usize ) -> Self :: Slice < ' _ > ;
4876}
4977
50- /// A no-op `Bitmap` implementation that can be provided for backends that do not actually
51- /// require the tracking functionality.
52- impl WithBitmapSlice < ' _ > for ( ) {
53- type S = Self ;
78+ impl Sliceable for ( ) {
79+ type Slice < ' a > = ( ) ;
5480}
5581
56- impl BitmapSlice for ( ) { }
57-
5882impl Bitmap for ( ) {
5983 fn mark_dirty ( & self , _offset : usize , _len : usize ) { }
6084
@@ -65,17 +89,12 @@ impl Bitmap for () {
6589 fn slice_at ( & self , _offset : usize ) -> Self { }
6690}
6791
68- /// A `Bitmap` and `BitmapSlice` implementation for `Option<B>`.
69- impl < ' a , B > WithBitmapSlice < ' a > for Option < B >
70- where
71- B : WithBitmapSlice < ' a > ,
72- {
73- type S = Option < B :: S > ;
92+ impl < B : Sliceable > Sliceable for Option < B > {
93+ type Slice < ' a > = Option < B :: Slice < ' a > > ;
7494}
7595
76- impl < B : BitmapSlice > BitmapSlice for Option < B > { }
77-
78- impl < B : Bitmap > Bitmap for Option < B > {
96+ impl < B : Bitmap > Bitmap for Option < B >
97+ {
7998 fn mark_dirty ( & self , offset : usize , len : usize ) {
8099 if let Some ( inner) = self {
81100 inner. mark_dirty ( offset, len)
@@ -89,7 +108,7 @@ impl<B: Bitmap> Bitmap for Option<B> {
89108 false
90109 }
91110
92- fn slice_at ( & self , offset : usize ) -> Option < < B as WithBitmapSlice > :: S > {
111+ fn slice_at ( & self , offset : usize ) -> Self :: Slice < ' _ > {
93112 if let Some ( inner) = self {
94113 return Some ( inner. slice_at ( offset) ) ;
95114 }
@@ -99,14 +118,15 @@ impl<B: Bitmap> Bitmap for Option<B> {
99118
100119/// Helper type alias for referring to the `BitmapSlice` concrete type associated with
101120/// an object `B: WithBitmapSlice<'a>`.
102- pub type BS < ' a , B > = <B as WithBitmapSlice < ' a > > :: S ;
121+ pub type BS < ' a , B > = <B as Sliceable > :: Slice < ' a > ;
103122
104123/// Helper type alias for referring to the `BitmapSlice` concrete type associated with
105124/// the memory regions of an object `M: GuestMemory`.
106125pub type MS < ' a , M > = BS < ' a , <<M as GuestMemory >:: R as GuestMemoryRegion >:: B > ;
107126
108127#[ cfg( test) ]
109128pub ( crate ) mod tests {
129+ use std:: fmt:: Debug ;
110130 use super :: * ;
111131
112132 use std:: io:: Cursor ;
0 commit comments