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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
//! # SNAFU Virtual Stack Trace
//!
//! A lightweight, efficient error handling library for Rust that implements virtual stack traces
//! based on [GreptimeDB's error handling approach](https://greptime.com/blogs/2024-05-07-error-rust).
//! This library combines the power of [SNAFU](https://github.com/shepmaster/snafu) error handling
//! with virtual stack traces to provide meaningful error context without the overhead of system backtraces.
//!
//! ## Motivation
//!
//! Traditional error handling in Rust often faces a dilemma:
//! - **Option 1:** Use system backtraces - long hard to read stack traces only referencing functions and lines
//! - **Option 2:** Simple error propagation - lacks context about where errors originated
//!
//! Virtual stack traces provide a third way: capturing meaningful context at each error propagation point with minimal overhead.
//!
//! ## Features
//!
//! - 🚀 **Lightweight**: Only ~100KB binary overhead vs several MB for system backtraces
//! - 📍 **Precise Location Tracking**: Automatically captures file, line, and column information
//! - 🔗 **Error Chain Walking**: Traverses the entire error source chain
//! - 🎯 **Zero-Cost Abstraction**: Context generation can be postponed until needed
//! - 🛠️ **Seamless Integration**: Works perfectly with SNAFU error handling
//! - 📝 **Developer-Friendly**: Automatic Debug implementation with formatted stack traces
//!
//! ## Basic Usage
//!
//! Simply add the `#[stack_trace_debug]` attribute to your SNAFU error enum:
//!
//! ```rust
//! use snafu::prelude::*;
//! use snafu_virtstack::stack_trace_debug;
//!
//! #[derive(Snafu)]
//! #[stack_trace_debug] // Add this attribute
//! enum MyError {
//! #[snafu(display("Failed to read file: {filename}"))]
//! FileRead { filename: String, source: std::io::Error },
//!
//! #[snafu(display("Invalid data format"))]
//! InvalidFormat { source: serde_json::Error },
//! }
//!
//! fn process_file(filename: &str) -> Result<String, MyError> {
//! let content = std::fs::read_to_string(filename)
//! .context(FileReadSnafu { filename })?;
//!
//! let data: serde_json::Value = serde_json::from_str(&content)
//! .context(InvalidFormatSnafu)?;
//!
//! Ok(data.to_string())
//! }
//! ```
//!
//! ## Generated Debug Output
//!
//! When an error occurs, the generated [`Debug`] implementation will display:
//!
//! ```text
//! Error: Failed to read file: config.json
//! Virtual Stack Trace:
//! 0: Failed to read file: config.json at src/main.rs:15:23
//! 1: No such file or directory (os error 2) at src/main.rs:16:10
//! ```
//!
//! ## Advanced Usage
//!
//! You can also access the virtual stack programmatically:
//!
//! ```rust
//! use snafu_virtstack::VirtualStackTrace;
//! # use snafu::prelude::*;
//! # use snafu_virtstack::stack_trace_debug;
//! # #[derive(Snafu)]
//! # #[stack_trace_debug]
//! # enum MyError {
//! # #[snafu(display("Something went wrong"))]
//! # SomethingWrong,
//! # }
//!
//! let error = MyError::SomethingWrong;
//! let stack = error.virtual_stack();
//!
//! for (i, frame) in stack.iter().enumerate() {
//! println!("Frame {}: {} at {}:{}",
//! i,
//! frame.message,
//! frame.location.file(),
//! frame.location.line()
//! );
//! }
//! ```
//!
//! ## Requirements
//!
//! - Must be applied to `enum` types only
//! - The enum should derive [`Snafu`] for full functionality
//! - Works best with error enums that have source fields for error chaining
//!
//! ## Performance Benefits
//!
//! The virtual stack trace approach provides several key advantages:
//!
//! ### 1. Performance Efficiency
//! Unlike system backtraces that capture the entire call stack (expensive operation),
//! virtual stack traces only record error propagation points. This results in:
//! - Lower CPU usage during error handling
//! - Reduced memory footprint
//! - Smaller binary sizes (100KB vs several MB)
//!
//! ### 2. Meaningful Context
//! Virtual stack traces capture:
//! - The exact location where each error was propagated
//! - Custom error messages at each level
//! - The complete error chain from root cause to final error
//!
//! ### 3. Production-Ready
//! - Safe to use in production environments
//! - No performance penalties in the happy path
//! - Can be enabled/disabled at runtime if needed
//!
//! ## How It Works
//!
//! 1. **Proc Macro Magic**: The [`stack_trace_debug`] attribute automatically implements:
//! - [`VirtualStackTrace`] trait for stack frame collection
//! - Custom [`Debug`] implementation for formatted output
//!
//! 2. **Location Tracking**: Uses Rust's `#[track_caller]` to capture precise locations
//! where errors are propagated
//!
//! 3. **Error Chain Walking**: Automatically traverses the `source()` chain to build
//! complete error context
//!
//! 4. **Zero-Cost Until Needed**: Stack frames are only generated when the error is
//! actually inspected
// Re-export the proc macro so users only need to depend on this crate
pub use stack_trace_debug;
/// Core trait for virtual stack trace functionality.
///
/// This trait is automatically implemented by the [`stack_trace_debug`] proc macro attribute.
/// It provides access to the virtual stack trace showing the error propagation path.
///
/// # Example
///
/// ```rust
/// use snafu::prelude::*;
/// use snafu_virtstack::{stack_trace_debug, VirtualStackTrace};
///
/// #[derive(Snafu)]
/// #[stack_trace_debug]
/// enum MyError {
/// #[snafu(display("Something went wrong"))]
/// SomethingWrong,
/// }
///
/// let error = MyError::SomethingWrong;
/// let stack = error.virtual_stack();
/// for frame in stack {
/// println!("{}", frame);
/// }
/// ```
/// Represents a single frame in the virtual stack trace.
///
/// Each frame captures the location where an error was propagated and the
/// associated error message. This provides precise context about the error
/// propagation path without the overhead of system backtraces.