n = "4"seed = "9"// A second module, so a step-in crosses a file boundary and the call trace// shows a frame whose source lives in a document the pane was not already// displaying.pub unconstrained fn mix(acc: u32, value: u32) -> u32 { let rotated = rotate(acc, 7); rotated ^ value}pub unconstrained fn finish(acc: u32) -> u32 { let folded = rotate(acc, 13); folded + 1}// The deepest frame in this module, and the only one with a loop in it — so a// step-out from here has a loop iteration to return into.unconstrained fn rotate(value: u32, by: u8) -> u32 { let mut out = value; for _ in 0..by { let carry = out & 1; out = (out >> 1) | (carry * 0x8000_0000); } out}// TOUR: calls and recursion//// The subject is the call trace. This program builds a call tree that is worth// looking at rather than a flat list: recursion that goes several frames deep,// two functions that call each other, and a helper called from three different// places so the same frame appears in the tree under three different parents.//// Stepping into, over and out of a frame all need somewhere to go, and a// program whose deepest call is one frame gives them nowhere.mod arith;unconstrained fn factorial(n: u32) -> u32 { // Direct recursion. Frame depth is `n + 1`, so calling it with 5 puts six // frames of the same function on the stack, each with a different `n` — // which is the case that distinguishes a call trace from a source view. if n <= 1 { 1 } else { n * factorial(n - 1) }}unconstrained fn is_even(n: u32) -> bool { // Mutual recursion, the pair. `is_even` and `is_odd` alternate all the way // down, so the trace shows two names interleaving rather than one repeating. if n == 0 { true } else { is_odd(n - 1) }}unconstrained fn is_odd(n: u32) -> bool { if n == 0 { false } else { is_even(n - 1) }}unconstrained fn fib(n: u32) -> u32 { // Tree recursion: each call makes TWO calls, so the trace branches instead // of descending. `fib(6)` is 25 calls — small enough to read, large enough // that the shape is a tree and not a line. if n < 2 { n } else { fib(n - 1) + fib(n - 2) }}unconstrained fn checksum(values: [u32; 4]) -> u32 { // A frame that calls into another module, so stepping in crosses a file // boundary and the source pane has to follow. let mut total: u32 = 0; for i in 0..4 { total = arith::mix(total, values[i]); } arith::finish(total)}unconstrained fn main(n: u32, seed: pub u32) -> pub u32 { let f = factorial(5); let even = is_even(n); let t = fib(6); let c = checksum([seed, seed + 1, seed + 2, seed + 3]); // `arith::mix` is reached from `checksum` above and directly from here, so // the same function has two distinct parents in the call trace. let direct = arith::mix(f, t); assert(f == 120); assert(t == 8); assert(even); // Both halves are folded into a small range before being added: this // program is about the shape of the call tree, and an arithmetic overflow // in its last line would end the recording somewhere uninteresting. (direct % 1000) + (c % 1000)}[package]name = "tour_calls"type = "bin"authors = ["BlockTracer capability tour"][dependencies]The recorded event stream is in the published recording. Reading it needs the replay engine, which this page has not started.
The call structure is in the published recording. Reading it needs the replay engine, which this page has not started.
The recorded values are in the published recording. Reading them needs the replay engine, which this page has not started.