pub struct CursorView<C: PageTableConfig> {
pub cur_va: Vaddr,
pub mappings: Set<Mapping>,
pub phantom: PhantomData<C>,
}Fields§
§cur_va: Vaddr§mappings: Set<Mapping>§phantom: PhantomData<C>Implementations§
Source§impl<C: PageTableConfig> CursorView<C>
impl<C: PageTableConfig> CursorView<C>
Sourcepub open spec fn non_overlapping(self) -> bool
pub open spec fn non_overlapping(self) -> bool
{
forall |m: Mapping, n: Mapping| {
self.mappings.contains(m)
==> (self.mappings.contains(n)
==> (m != n
==> m.va_range.end <= n.va_range.start
|| n.va_range.end <= m.va_range.start))
}
}Mappings in the view are non-overlapping. This is a consequence of the page table tree structure: distinct paths map to disjoint VA ranges.
Source§impl<C: PageTableConfig> CursorView<C>
A CursorView is not aware that the underlying structure of the page table is a tree.
It treats the page table as an array of mappings of various sizes, and the cursor itself as the
current virtual address, moving from low to high addresses. These functions specify its behavior
and provide a simple interface for reasoning about its behavior.
impl<C: PageTableConfig> CursorView<C>
A CursorView is not aware that the underlying structure of the page table is a tree.
It treats the page table as an array of mappings of various sizes, and the cursor itself as the
current virtual address, moving from low to high addresses. These functions specify its behavior
and provide a simple interface for reasoning about its behavior.
Sourcepub open spec fn item_into_mapping(va: Vaddr, item: C::Item) -> Mapping
pub open spec fn item_into_mapping(va: Vaddr, item: C::Item) -> Mapping
{
let (paddr, level, prop, _perm) = C::item_into_raw(item);
let size = page_size::<PagingConsts>(level);
Mapping {
va_range: va as int..va + size,
pa_range: paddr..(paddr + size) as Paddr,
page_size: size,
property: prop,
}
}Sourcepub open spec fn present(self) -> bool
pub open spec fn present(self) -> bool
{
self
.mappings
.filter(|m: Mapping| m.va_range.start <= self.cur_va < m.va_range.end)
.len() > 0
}This function checks if the current virtual address is mapped. It does not correspond to a cursor method itself, but defines what it means for an entry to present: there is a mapping whose virtual address range contains the current virtual address.
Sourcepub open spec fn query_mapping(self) -> Mapping
pub open spec fn query_mapping(self) -> Mapping
self.present(),{
self.mappings
.filter(|m: Mapping| m.va_range.start <= self.cur_va < m.va_range.end)
.choose()
}Sourcepub open spec fn query(self, paddr: Paddr, size: usize, prop: PageProperty) -> bool
pub open spec fn query(self, paddr: Paddr, size: usize, prop: PageProperty) -> bool
{
let m = self.query_mapping();
m.pa_range.start == paddr && m.page_size == size && m.property == prop
}Sourcepub open spec fn query_range(self) -> Range<int>
pub open spec fn query_range(self) -> Range<int>
{ self.query_mapping().va_range }Sourcepub open spec fn cur_slot_range(self, size: usize) -> Range<int>
pub open spec fn cur_slot_range(self, size: usize) -> Range<int>
{
let start = nat_align_down(self.cur_va as nat, size as nat) as int;
start..start + size
}The VA range of the current slot when mapping a page of the given size. Works for both present and absent mappings: when present, equals query_range() for a mapping of that size; when absent, returns the aligned range that would be mapped.
Sourcepub open spec fn query_item_spec(self, item: C::Item) -> Option<Range<Vaddr>>
pub open spec fn query_item_spec(self, item: C::Item) -> Option<Range<Vaddr>>
self.present(),{
let (paddr, level, prop, _perm) = C::item_into_raw_spec(item);
let size = page_size::<PagingConsts>(level);
if self.query(paddr, size, prop) {
let r = self.query_range();
Some(r.start as Vaddr..r.end as Vaddr)
} else {
None
}
}This predicate specifies the behavior of the query method. It states that the current item
in the page table matches the given item, mapped at the resulting virtual address range.
Sourcepub open spec fn jump_spec(self, va: usize) -> Self
pub open spec fn jump_spec(self, va: usize) -> Self
{
CursorView {
cur_va: va as Vaddr,
..self
}
}Jump just sets the current virtual address to the given address.
Sourcepub open spec fn align_up_spec(self, size: usize) -> Vaddr
pub open spec fn align_up_spec(self, size: usize) -> Vaddr
{ (nat_align_down(self.cur_va as nat, size as nat) + size as nat) as Vaddr }Post-map cursor position: always advance by size from the aligned base.
Matches cursor.map exec semantics (always calls move_forward, advancing by
page_size(level) regardless of alignment).
Do NOT substitute vstd_extra::arithmetic::nat_align_up here — that function
leaves already-aligned inputs unchanged, which would mismatch exec.
Sourcepub open spec fn split_index(m: Mapping, new_size: usize, n: usize) -> Mapping
pub open spec fn split_index(m: Mapping, new_size: usize, n: usize) -> Mapping
{
Mapping {
va_range: m.va_range.start + n * new_size..m.va_range.start + (n + 1) * new_size,
pa_range: (m.pa_range.start + n * new_size)
as usize..(m.pa_range.start + (n + 1) * new_size) as usize,
page_size: new_size,
property: m.property,
}
}Sourcepub open spec fn split_if_mapped_huge_spec(self, new_size: usize) -> Self
pub open spec fn split_if_mapped_huge_spec(self, new_size: usize) -> Self
{
let m = self.query_mapping();
let size = m.page_size;
let new_mappings = Set::<int>::range(0int, (size / new_size) as int)
.map(|n: int| Self::split_index(m, new_size, n as usize));
CursorView {
cur_va: self.cur_va,
mappings: self.mappings - set![m] + new_mappings,
..self
}
}Sourcepub open spec fn split_while_huge(self, size: usize) -> Self
pub open spec fn split_while_huge(self, size: usize) -> Self
{
if self.present() {
let m = self.query_mapping();
if m.page_size > size {
let new_size = m.page_size / NR_ENTRIES;
let new_self = self.split_if_mapped_huge_spec(new_size);
new_self.split_while_huge(size)
} else {
self
}
} else {
self
}
}Sourcepub open spec fn remove_subtree(self, size: usize) -> Set<Mapping>
pub open spec fn remove_subtree(self, size: usize) -> Set<Mapping>
{
let start = nat_align_down(self.cur_va as nat, size as nat) as Vaddr;
let subtree = self
.mappings
.filter(|m: Mapping| start <= m.va_range.start < start + size);
self.mappings - subtree
}Sourcepub open spec fn map_spec(self, paddr: Paddr, size: usize, prop: PageProperty) -> Self
pub open spec fn map_spec(self, paddr: Paddr, size: usize, prop: PageProperty) -> Self
{
let new = Mapping {
va_range: self.cur_slot_range(size),
pa_range: paddr..(paddr + size) as usize,
page_size: size,
property: prop,
};
let split_self = self.split_while_huge(size);
CursorView {
cur_va: split_self.align_up_spec(size),
mappings: split_self.remove_subtree(size) + set![new],
..split_self
}
}Inserts a mapping into the cursor. If there were previously mappings there, they are removed. Note that multiple mappings might be removed if they overlap with a new large mapping.
Sourcepub open spec fn map_simple(self, paddr: Paddr, size: usize, prop: PageProperty) -> Self
pub open spec fn map_simple(self, paddr: Paddr, size: usize, prop: PageProperty) -> Self
{
let new = Mapping {
va_range: self.cur_slot_range(size),
pa_range: paddr..(paddr + size) as usize,
page_size: size,
property: prop,
};
CursorView {
cur_va: self.cur_va,
mappings: self.mappings + set![new],
..self
}
}Sourcepub open spec fn unmap_spec(self, len: usize, new_view: Self, num_unmapped: usize) -> bool
pub open spec fn unmap_spec(self, len: usize, new_view: Self, num_unmapped: usize) -> bool
{
let start = self.cur_va;
let end = (self.cur_va + len) as Vaddr;
&&& new_view.cur_va >= end
&&& forall |m: Mapping| {
#[trigger] self.mappings.contains(m)
&& (m.va_range.end <= start || m.va_range.start >= end)
==> new_view.mappings.contains(m)
}
&&& forall |m: Mapping| {
new_view.mappings.contains(m) && start <= m.va_range.start < end
==> exists |parent: Mapping| {
#[trigger] self.mappings.contains(parent)
&& parent.va_range.start < start
&& parent.va_range.start <= m.va_range.start
&& m.va_range.end <= parent.va_range.end
&& m.pa_range.start
== (parent.pa_range.start
+ (m.va_range.start - parent.va_range.start)) as Paddr
&& m.property == parent.property
}
}
&&& forall |m: Mapping| {
#[trigger] new_view.mappings.contains(m)
==> self.mappings.contains(m)
|| exists |parent: Mapping| {
#[trigger] self.mappings.contains(parent)
&& parent.va_range.start <= m.va_range.start
&& m.va_range.end <= parent.va_range.end
&& m.pa_range.start
== (parent.pa_range.start
+ (m.va_range.start - parent.va_range.start)) as Paddr
&& m.property == parent.property
}
}
}Unmaps a range of virtual addresses from the current address up to len bytes.
It returns the number of mappings that were removed.
Because the implementation may split huge pages that straddle the range
boundaries, the spec first applies split_while_huge at both cur_va
and cur_va + len to obtain a “base” set of mappings where all boundary
entries are at the finest granularity. Mappings whose va_range.start
falls in [cur_va, cur_va + len) are then removed from this base.
Source§impl<C: PageTableConfig> CursorView<C>
impl<C: PageTableConfig> CursorView<C>
Sourcepub proof fn split_if_mapped_huge_spec_preserves_present(v: Self, new_size: usize)
pub proof fn split_if_mapped_huge_spec_preserves_present(v: Self, new_size: usize)
v.inv(),v.present(),new_size > 0,v.query_mapping().page_size > 0,v.query_mapping().page_size % new_size == 0,ensuresv.split_if_mapped_huge_spec(new_size).present(),After split_if_mapped_huge_spec(new_size), a sub-mapping at cur_va
still exists. The witness is split_index(m, new_size, k) where
k = (cur_va - m.va_range.start) / new_size.
Sourcepub proof fn split_if_mapped_huge_spec_decreases_page_size(v: Self, new_size: usize)
pub proof fn split_if_mapped_huge_spec_decreases_page_size(v: Self, new_size: usize)
v.inv(),v.present(),new_size > 0,v.query_mapping().page_size > new_size,v.query_mapping().page_size % new_size == 0,ensuresv.split_if_mapped_huge_spec(new_size).present(),v.split_if_mapped_huge_spec(new_size).query_mapping().page_size
< v.query_mapping().page_size,After split_if_mapped_huge_spec(new_size) on a valid view, the
mapping at cur_va has page_size == new_size < m.page_size.
The sub-mapping split_index(m, new_size, k) has page_size = new_size.
No other mapping from the original view covers cur_va (non-overlapping),
so query_mapping() must return a sub-mapping with page_size = new_size.
Sourcepub proof fn split_if_mapped_huge_spec_preserves_inv(v: Self, new_size: usize)
pub proof fn split_if_mapped_huge_spec_preserves_inv(v: Self, new_size: usize)
v.inv(),v.present(),new_size > 0,v.query_mapping().page_size > new_size,v.query_mapping().page_size % new_size == 0,set![4096usize, 2097152, 1073741824].contains(new_size),ensuresv.split_if_mapped_huge_spec(new_size).inv(),split_if_mapped_huge_spec preserves CursorView::inv().
Requires: v.inv(), v.present(), the mapping at cur_va has
page_size > new_size, page_size % new_size == 0, and new_size
is itself a valid page size.
Sourcepub broadcast proof fn lemma_split_while_huge_preserves_cur_va(self, size: usize)
pub broadcast proof fn lemma_split_while_huge_preserves_cur_va(self, size: usize)
self.inv(),size >= PAGE_SIZE,ensures#[trigger] self.split_while_huge(size).cur_va == self.cur_va,split_while_huge only modifies mappings, not cur_va.
Sourcepub proof fn lemma_split_while_huge_preserves_inv(self, size: usize)
pub proof fn lemma_split_while_huge_preserves_inv(self, size: usize)
self.inv(),size >= PAGE_SIZE,ensuresself.split_while_huge(size).inv(),split_while_huge preserves CursorView::inv().
Sourcepub proof fn split_while_huge_compose(self, s1: usize, s2: usize)
pub proof fn split_while_huge_compose(self, s1: usize, s2: usize)
self.inv(),s1 >= PAGE_SIZE,s2 <= s1,ensuresself.split_while_huge(s2) == self.split_while_huge(s1).split_while_huge(s2),Composition law for split_while_huge:
splitting to a finer target s2 <= s1 is the same as first splitting to s1 and then
further splitting to s2.
Sourcepub proof fn split_while_huge_noop_implies_page_size_le(self, size: usize)
pub proof fn split_while_huge_noop_implies_page_size_le(self, size: usize)
self.inv(),size >= PAGE_SIZE,self.split_while_huge(size) == self,self.present(),ensuresself.query_mapping().page_size <= size,When split_while_huge(size) is a no-op and the view is present(),
the mapping at cur_va already has page_size <= size.
Sourcepub proof fn split_while_huge_one_step(self, size: usize)
pub proof fn split_while_huge_one_step(self, size: usize)
self.inv(),self.present(),self.query_mapping().page_size > size,self.query_mapping().page_size / NR_ENTRIES == size,self.query_mapping().page_size % size == 0,set![4096usize, 2097152, 1073741824].contains(size),ensuresself.split_while_huge(size).mappings == self.split_if_mapped_huge_spec(size).mappings,When the mapping at cur_va is exactly one split-step above size
(i.e. query_mapping().page_size / NR_ENTRIES == size), one step of
split_while_huge equals split_if_mapped_huge_spec:
self.split_while_huge(size) == self.split_if_mapped_huge_spec(size)
This is because split_while_huge takes one step
split_if_mapped_huge_spec(m.page_size / NR_ENTRIES) = split_if_mapped_huge_spec(size),
then the sub-mapping at cur_va has page_size == size <= size, so it stops.
Sourcepub proof fn split_while_huge_locality(self, size: usize, m2: Mapping)
pub proof fn split_while_huge_locality(self, size: usize, m2: Mapping)
self.inv(),size >= PAGE_SIZE,self.mappings.contains(m2),!(m2.va_range.start <= self.cur_va < m2.va_range.end),ensuresself.split_while_huge(size).mappings.contains(m2),Locality of split_while_huge: a mapping m2 that is in self.mappings
and whose VA range does not contain cur_va is preserved.
Sourcepub proof fn split_if_mapped_huge_spec_refinement(self, new_size: usize, e: Mapping)
pub proof fn split_if_mapped_huge_spec_refinement(self, new_size: usize, e: Mapping)
self.inv(),self.present(),new_size > 0,self.query_mapping().page_size > new_size,self.query_mapping().page_size % new_size == 0,self.split_if_mapped_huge_spec(new_size).mappings.contains(e),ensuresself.mappings.contains(e)
|| {
let parent = self.query_mapping();
&&& self.mappings.contains(parent)
&&& parent.va_range.start <= e.va_range.start
&&& e.va_range.end <= parent.va_range.end
&&& e.pa_range.start
== (parent.pa_range.start + (e.va_range.start - parent.va_range.start))
as Paddr
&&& e.property == parent.property
},Refinement: every mapping in split_while_huge(size).mappings is either
from self.mappings or a sub-mapping of an entry in self.mappings.
Base lemma: every mapping in split_if_mapped_huge_spec(new_size).mappings
is either from the original mappings or a sub-mapping of query_mapping().
Sourcepub proof fn split_while_huge_refinement(self, size: usize, m: Mapping)
pub proof fn split_while_huge_refinement(self, size: usize, m: Mapping)
self.inv(),size >= PAGE_SIZE,self.split_while_huge(size).mappings.contains(m),ensuresself.mappings.contains(m)
|| exists |parent: Mapping| {
#[trigger] self.mappings.contains(parent)
&& parent.va_range.start <= m.va_range.start
&& m.va_range.end <= parent.va_range.end
&& m.pa_range.start
== (parent.pa_range.start + (m.va_range.start - parent.va_range.start))
as Paddr && m.property == parent.property
},Sourcepub proof fn split_while_huge_disjoint(self, size: usize, other: Set<Mapping>)
pub proof fn split_while_huge_disjoint(self, size: usize, other: Set<Mapping>)
self.inv(),size >= PAGE_SIZE,forall |m: Mapping, x: Mapping| {
#[trigger] self.mappings.contains(m) && #[trigger] other.contains(x)
==> Mapping::disjoint_vaddrs(m, x)
},ensuresself.split_while_huge(size).mappings.disjoint(other),split_while_huge produces a set disjoint from any set that is
pairwise VA-disjoint from self.mappings.
Set-disjointness of other from self.mappings is not sufficient
(counterexample: other = {split_index(m, k, 0)} collides with the
first sub-mapping after one split step). We need VA-disjointness so
that sub-mappings — which lie strictly inside the parent’s va_range
and hence have distinct va_ranges from anything in other — cannot
equal any element of other.
Trait Implementations§
Source§impl<C: PageTableConfig> Inv for CursorView<C>
impl<C: PageTableConfig> Inv for CursorView<C>
Auto Trait Implementations§
impl<C> Freeze for CursorView<C>
impl<C> RefUnwindSafe for CursorView<C>where
C: RefUnwindSafe,
impl<C> Send for CursorView<C>
impl<C> Sync for CursorView<C>
impl<C> Unpin for CursorView<C>where
C: Unpin,
impl<C> UnsafeUnpin for CursorView<C>
impl<C> UnwindSafe for CursorView<C>where
C: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T, VERUS_SPEC__A> FromSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: From<T>,
impl<T, VERUS_SPEC__A> FromSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: From<T>,
fn obeys_from_spec() -> bool
fn from_spec(v: T) -> VERUS_SPEC__A
§impl<T, VERUS_SPEC__A> IntoSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: Into<T>,
impl<T, VERUS_SPEC__A> IntoSpec<T> for VERUS_SPEC__Awhere
VERUS_SPEC__A: Into<T>,
fn obeys_into_spec() -> bool
fn into_spec(self) -> T
§impl<T, U> IntoSpecImpl<U> for Twhere
U: From<T>,
impl<T, U> IntoSpecImpl<U> for Twhere
U: From<T>,
fn obeys_into_spec() -> bool
fn into_spec(self) -> U
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<A> SpecEq<&A> for Awhere
A: ?Sized,
impl<A> SpecEq<&mut A> for Awhere
A: ?Sized,
impl<A> SpecEq<A> for Awhere
A: ?Sized,
impl<A> SpecEq<Ghost<A>> for A
impl<A> SpecEq<Tracked<A>> for A
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.