1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! Rust has a problematic relationship with recursive functions, because functions that recurse
//! deeply can overflow the stack, crashing your program. This crate makes it easy to remedy
//! this problem by marking (indirectly) recursive functions as such:
//! ```rust
//! use recursive::recursive;
//!
//! #[recursive]
//! fn sum(nums: &[u64]) -> u64 {
//! if let Some((head, tail)) = nums.split_first() {
//! head + sum(tail)
//! } else {
//! 0
//! }
//! }
//! ```
//!
//! The way this prevents stack overflows is by checking the size of the remaining stack at the
//! start of each call to your function. If this size is under a boundary set by
//! [`set_minimum_stack_size`] (by default 128 KiB), a new stack is allocated and execution
//! continues on that stack. This new stack's size is set using [`set_stack_allocation_size`], which
//! is 2 MiB by default.
//!
//! This crate works by wrapping your function body in a call to [`stacker::maybe_grow`]. If this
//! crate is not flexible enough for your needs consider using [`stacker`] directly yourself.
//!
//! ## What are the downsides?
//!
//! This crate is **not** zero cost, but it is also not limited to simple tail recursion or direct
//! recursion. However, in most cases the stack size test is very fast and almost always succeeds
//! without needing to allocate. If your recursive algorithm is very performance-sensitive I would
//! suggest rewriting it to an iterative version regardless.
//!
//! This crate only supports those platforms that [`stacker`] supports. The Rust compiler itself
//! uses [`stacker`], so the platform you're compiling on should always be fine, but for more
//! obscure targets see its documentation.
//!
//! ## Which functions should I mark as `#[recursive]`?
//!
//! Any function that directly calls itself should be marked as `#[recursive]`, unless you know for
//! certain that the stack is sufficiently large for any inputs that function will be called with.
//! If you are feeding untrusted input into a recursive function you should always mark it as
//! `#[recursive]`.
//!
//! It is not necessary to mark every single function that can indirectly recurse as `#[recursive]`.
//! As long as every possible cycle of function calls includes at least one function marked
//! `#[recursive]` you will be protected against stack overflows due to recursion.
use ;
// These are referred to only by the procedural macro.
/// Marks a function to use an automatically growing segmented stack.
///
/// See the [crate docs](crate) for details.
pub use recursive;
static MINIMUM_STACK_SIZE: AtomicUsize = new;
static STACK_ALLOC_SIZE: AtomicUsize = new;
/// This sets the minimum stack size that [`recursive`] requires.
///
/// If a function tagged with `#[recursive]` is called when the remaining stack size is less than
/// this value a new stack gets allocated.
///
/// The default value if this function is never called is 128 KiB.
/// Returns the value set by [`set_minimum_stack_size`].
/// When a new stack gets allocated it will get allocated with this size.
///
/// The default value if this function is never called is 2 MiB.
/// Returns the value set by [`set_stack_allocation_size`].