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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// Copyright (c) 2023-2025 R3BL LLC. Licensed under Apache License, Version 2.0.
//! Trait for high-performance string building for complex types. See [`FastStringify`],
//! [`BufTextStorage`] and [`generate_impl_display_for_fast_stringify!`] for details.
//!
//! [`generate_impl_display_for_fast_stringify!`]: crate::generate_impl_display_for_fast_stringify
use ;
/// High-performance string building for complex types that avoids formatter overhead.
///
/// This trait requires [`Display`] as a supertrait, meaning any type implementing
/// [`FastStringify`] **must also implement** [`Display`]. This allows the trait to
/// provide optimized string building while maintaining compatibility with Rust's
/// standard formatting infrastructure.
///
/// # How to Implement
///
/// Both [`FastStringify`] and [`Display`] must be implemented, but the [`Display`]
/// implementation is always the same boilerplate. Use the [`generate_impl_display_for_fast_stringify!`]
/// macro to generate it automatically.
///
/// 1. **Implement [`write_to_buf()`]** with your custom formatting logic
/// 2. **Call the macro** [`generate_impl_display_for_fast_stringify!`] to generate the [`Display`] implementation
///
/// [`generate_impl_display_for_fast_stringify!`]: crate::generate_impl_display_for_fast_stringify
///
/// ```rust
/// # use r3bl_tui::{FastStringify, BufTextStorage, generate_impl_display_for_fast_stringify};
/// # use std::fmt::{Result, Write};
/// # struct MyType { value: i32 }
/// impl FastStringify for MyType {
/// fn write_to_buf(&self, acc: &mut BufTextStorage) -> Result {
/// acc.push_str("MyType { value: ");
/// write!(acc, "{}", self.value)?; // Use write! only when formatting needed
/// acc.push_str(" }");
/// Ok(())
/// }
/// }
///
/// // ✨ One line instead of 5-line Display impl!
/// generate_impl_display_for_fast_stringify!(MyType);
/// ```
///
/// # Why Use This?
///
/// The standard [`Display`] trait using [`Formatter`] has significant overhead for types
/// that build strings from many pieces. Each [`write!`] call goes through the formatter's
/// state machine, checking flags and doing bounds checks. [`FastStringify`] batches all
/// content into a single buffer, then makes ONE write to the formatter using
/// [`write_str`], reducing overhead from ~16% to ~5-8% in performance profiles.
///
/// # Performance Hierarchy (fastest to slowest)
///
/// 1. **Direct `push_str()`** - The absolute fastest when you have a `&str`
///
/// ```rust
/// # let mut buffer = String::new();
/// buffer.push_str("Hello, world!"); // Zero overhead, direct memory copy
/// ```
///
/// 2. **[`FastStringify`] trait** - Fast batched writing for complex types. See
/// [implementation example] above.
///
/// 3. **[`write!`] with [`FormatArgs`]** - Slowest due to formatting overhead
///
/// ```rust
/// # use std::fmt::Write;
/// # let mut buffer = String::new();
/// # let value = 42;
/// // Goes through formatter state machine
/// write!(buffer, "Value: {}", value)?;
/// # Ok::<(), std::fmt::Error>(())
/// ```
///
/// [implementation example]: #how-to-implement
/// [`Display`]: Display
/// [`Formatter`]: std::fmt::Formatter
/// [`write!`]: std::write
/// [`write_str`]: std::fmt::Formatter::write_str
/// [`FormatArgs`]: std::fmt::Arguments
/// [`push_str`]: String::push_str
/// [`write_to_buf()`]: FastStringify::write_to_buf
/// [`write_buf_to_fmt()`]: FastStringify::write_buf_to_fmt
/// Buffer for building text efficiently.
///
/// We use [`String`] as the backing storage after performance testing showed:
/// - [`SmallString<[u8; 64]>`] had slightly worse performance due to stack allocation
/// overhead.
/// - [`SmallString<[u8; 256]>`] had even worse performance for small strings.
/// - Plain [`String`] provides the best balance of performance across all test cases.
///
/// # Why [`String`] Wins for Short-Lived Buffers
///
/// This buffer is created fresh in every [`Display::fmt`] call and immediately dropped
/// after use, making it extremely short-lived. For this usage pattern, [`String`]
/// outperforms `SmallString` because:
///
/// ## Stack Allocation Cost
///
/// - [`SmallString<[u8; 256]>`] allocates 256 bytes on the stack **every time**,
/// regardless of actual usage
/// - This touches multiple CPU cache lines (typically 64 bytes each) just to set up the
/// buffer
/// - [`String`] only allocates 24 bytes on the stack (pointer, length, capacity), with
/// actual content on the heap
///
/// ## Unpredictable Size Problem
///
/// Types implementing [`FastStringify`] have unpredictable output sizes:
/// - ANSI styled text: `"\x1b[38;5;42mHello\x1b[0m"` ≈ 20 bytes
/// - Complex types: could be 10 bytes or 500 bytes
/// - With [`SmallString<[u8; 64]>`]: waste stack space for small strings, pay both stack
/// AND heap for large strings
/// - With [`String`]: only pay for what you actually use
///
/// ## Modern Allocator Efficiency
///
/// For short-lived heap allocations, modern allocators are highly optimized:
/// - Thread-local caches make allocation often just a pointer bump
/// - Deallocation returns memory to thread-local free list for immediate reuse
/// - The next [`Display::fmt`] call likely reuses the same heap block
///
/// ## Example Comparison
///
/// ```text
/// SmallString<[u8; 256]> approach:
/// - Stack: 256 bytes allocated upfront
/// - Typical usage: 20 bytes
/// - Wasted: 236 bytes per call
///
/// String approach:
/// - Stack: 24 bytes (ptr, len, cap)
/// - Heap: ~32 bytes (only when needed)
/// - Wasted: ~12 bytes on heap (better locality)
/// ```
///
/// ## When [`smallstr::SmallString`] Would Win
///
/// [`smallstr::SmallString`] would be better if the buffer was:
/// - **Long-lived**: Amortizes stack allocation over many operations
/// - **Predictable size**: 90%+ of strings fit in inline capacity
/// - **Hot loop**: Allocator pressure becomes a bottleneck
///
/// But for this use case (short-lived, unpredictable size), [`String`] is optimal.
///
/// This type alias allows us to easily experiment with different string-like data
/// structures in the future without impacting the rest of the codebase.
///
/// [`String`]: std::string::String
/// [`Display::fmt`]: Display::fmt
/// [`SmallString<[u8; 64]>`]: `smallstr::SmallString`
/// [`SmallString<[u8; 256]>`]: `smallstr::SmallString`
pub type BufTextStorage = String;
/// Macro to implement the boilerplate [`Display`] trait for types implementing
/// [`FastStringify`].
///
/// This macro eliminates the repetitive 5-line [`Display`] implementation that's
/// identical for all types using [`FastStringify`]. Instead of manually writing the
/// [`Display`] impl, just call this macro after your [`FastStringify`] implementation.
///
/// # Basic Usage
///
/// ```rust
/// # use r3bl_tui::{FastStringify, BufTextStorage, generate_impl_display_for_fast_stringify};
/// # use std::fmt::{Result, Write};
/// struct MyType { value: i32 }
///
/// impl FastStringify for MyType {
/// fn write_to_buf(&self, acc: &mut BufTextStorage) -> Result {
/// acc.push_str("MyType { value: ");
/// write!(acc, "{}", self.value)?;
/// acc.push_str(" }");
/// Ok(())
/// }
/// }
///
/// // Single line instead of 5-line Display impl!
/// generate_impl_display_for_fast_stringify!(MyType);
/// ```
///
/// [`Display`]: std::fmt::Display
/// [`FastStringify`]: FastStringify