[−][src]Struct topo::CallId
Identifies the scope of a nested function call in a way that can be deterministically reproduced across multiple executions.
The CallId::current
for a function call is the combined product of:
- a callsite: the
std::panic::Location
where the function was called - a parent: the
CallId::current
which was active when calling the function - a slot: a value indicating the call's "index" within the parent call
When a nested call returns or unwinds, it reverts CallId::current
to
the parent CallId
.
Example
use topo::{call, root, CallId}; let returns_two_ids = || { let first = call(|| CallId::current()); let second = call(|| CallId::current()); assert_ne!(first, second, "these are always distinct calls"); (first, second) }; // running the closure as a nested call(...) gives different siblings assert_ne!(call(returns_two_ids), call(returns_two_ids)); // a call to root(...) gives each of these closure calls an identical parent CallId assert_eq!(root(returns_two_ids), root(returns_two_ids));
Creation
Every CallId
is created by calling one of:
- a function marked
nested
- a function passed to
call
- a function and slot passed to
call_in_slot
Slots
Slots are used to differentiate between repeated calls at the same callsite
and define the "index" of a child call within its parent. By default (and in
call
) the slot is populated by the number of times the current
callsite has been called in this parent. Users can provide their own slot
with call_in_slot
or using #[topo::nested(slot = "...")]
:
See call_in_slot
and nested
for examples.
Roots
The topmost parent or "root" of a callgraph can be defined in two ways:
- a
call
orcall_in_slot
invocation with no parent implicitly creates its own root - an explicit call to
root
creates a new subgraph regardless of the current parent
See root
for examples.
CallId
and multiple threads
The illicit
environment used for tracking the current CallId
is
thread-local, but values used to track slots are
interned in a global cache. This means that two different threads calling
an identical chain of nested functions can observe identical CallId
s:
use std::{ sync::mpsc::{channel, Sender}, thread, }; let (send_ids, recv_ids) = channel(); let spawn_worker = |sender: Sender<(CallId, CallId)>| { thread::spawn(move || sender.send(root(returns_two_ids)).unwrap()) }; let first_thread = spawn_worker(send_ids.clone()); let second_thread = spawn_worker(send_ids); first_thread.join().unwrap(); second_thread.join().unwrap(); // the two worker threads "did the same work" assert_eq!(recv_ids.recv()?, recv_ids.recv()?);
Implementations
impl CallId
[src]
Trait Implementations
impl Clone for CallId
[src]
impl Copy for CallId
[src]
impl Debug for CallId
[src]
impl Eq for CallId
[src]
impl Hash for CallId
[src]
fn hash<__H: Hasher>(&self, state: &mut __H)
[src]
fn hash_slice<H>(data: &[Self], state: &mut H) where
H: Hasher,
1.3.0[src]
H: Hasher,
impl PartialEq<CallId> for CallId
[src]
impl StructuralEq for CallId
[src]
impl StructuralPartialEq for CallId
[src]
Auto Trait Implementations
impl RefUnwindSafe for CallId
impl Send for CallId
impl Sync for CallId
impl Unpin for CallId
impl UnwindSafe for CallId
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> AsContext for T where
T: Debug + 'static,
[src]
T: Debug + 'static,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> Downcast for T where
T: Any,
T: Any,
fn into_any(self: Box<T>) -> Box<dyn Any + 'static>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>
fn as_any(&self) -> &(dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
impl<T> DowncastSync for T where
T: Send + Sync + Any,
T: Send + Sync + Any,
impl<T> Erased for T
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> ToOwned for T where
T: Clone,
[src]
T: Clone,
type Owned = T
The resulting type after obtaining ownership.
fn to_owned(&self) -> T
[src]
fn clone_into(&self, target: &mut T)
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,