use std::cell::Cell;
use std::future::Future;
thread_local! {
static ENTRIES: Cell<(usize, usize)> = const { Cell::new((0, 0)) };
}
#[inline(never)]
fn position() -> usize {
let marker = 0u8;
std::hint::black_box(std::ptr::addr_of!(marker)).addr()
}
fn entries() -> (usize, usize) {
ENTRIES.try_with(Cell::get).unwrap_or((0, 0))
}
fn set_entries(value: (usize, usize)) {
let _ = ENTRIES.try_with(|entries| entries.set(value));
}
pub(crate) struct Entry(());
impl Entry {
pub(crate) fn begin() -> Self {
let (base, live) = entries();
let base = if live == 0 { position() } else { base };
set_entries((base, live.saturating_add(1)));
Entry(())
}
}
impl Drop for Entry {
fn drop(&mut self) {
let (base, live) = entries();
set_entries((base, live.saturating_sub(1)));
}
}
pub(crate) fn nested_bytes() -> usize {
match entries() {
(base, live) if live > 1 => base.abs_diff(position()),
_ => 0,
}
}
pub(crate) async fn per_poll<F: Future>(future: F) -> F::Output {
let mut future = std::pin::pin!(future);
std::future::poll_fn(|cx| {
let _entry = Entry::begin();
future.as_mut().poll(cx)
})
.await
}