pub struct ScratchBuffers {
pub digit_buffer: DigitBuffer,
pub byte_buffer: Vec<u8>,
pub string_buffer: String,
}Expand description
Reusable scratch buffers for worker threads
Pre-allocated buffers that can be reused across multiple record processing operations to minimize heap allocations in hot codec paths. This is a critical performance optimization that eliminates allocation overhead during high-throughput data processing.
§Usage Pattern
- Create once per worker thread:
ScratchBuffers::new() - Use buffers during record processing
- Clear buffers after each record:
clear() - Reuse for next record (no reallocation)
§Performance Benefits
- Zero allocations in steady-state processing (after initial capacity growth)
- CPU cache-friendly - buffers stay hot in L1/L2 cache
- Reduced GC pressure - minimal heap churn
- Thread-local - no synchronization overhead
§Buffer Purposes
digit_buffer- Packed/zoned decimal digit extraction (stack-allocated up to 32 bytes)byte_buffer- General-purpose byte storage (EBCDIC conversion, field data)string_buffer- UTF-8 text processing (field values, JSON strings)
§Examples
§Basic Usage
use copybook_codec_memory::ScratchBuffers;
let mut scratch = ScratchBuffers::new();
// Use buffers for processing
scratch.digit_buffer.push(5);
scratch.byte_buffer.extend_from_slice(b"EBCDIC data");
scratch.string_buffer.push_str("converted text");
// Clear for next record (no deallocation)
scratch.clear();
assert_eq!(scratch.digit_buffer.len(), 0);
assert_eq!(scratch.byte_buffer.len(), 0);
assert_eq!(scratch.string_buffer.len(), 0);§Integration with Codec Functions
use copybook_codec_memory::ScratchBuffers;
use copybook_codec::{decode_record_with_scratch, DecodeOptions};
use copybook_core::parse_copybook;
let copybook = "01 RECORD.\n 05 FIELD PIC X(10).";
let schema = parse_copybook(copybook).unwrap();
let data = vec![0xF1; 10]; // EBCDIC '1' repeated
let mut scratch = ScratchBuffers::new();
let options = DecodeOptions::new();
// Process records in loop (reusing scratch buffers)
for _ in 0..1000 {
let _value = decode_record_with_scratch(&schema, &data, &options, &mut scratch).unwrap();
scratch.clear(); // Reuse buffers for next record
}§Capacity Management
use copybook_codec_memory::ScratchBuffers;
let mut scratch = ScratchBuffers::new();
// Pre-allocate for large records
scratch.ensure_byte_capacity(8192); // 8 KB record size
scratch.ensure_string_capacity(4096); // 4 KB string fields
// Buffers now have sufficient capacity for processing
assert!(scratch.byte_buffer.capacity() >= 8192);
assert!(scratch.string_buffer.capacity() >= 4096);Fields§
§digit_buffer: DigitBufferBuffer for digit processing in packed/zoned decimal codecs
Stack-allocated up to 32 bytes (typical COBOL numerics), then spills to heap.
byte_buffer: Vec<u8>General-purpose byte buffer for record processing
Used for EBCDIC conversion, field extraction, and intermediate data storage. Initial capacity: 1 KB.
string_buffer: StringString buffer for text processing
Used for UTF-8 text fields, JSON string construction, and character conversion. Initial capacity: 512 characters.
Implementations§
Source§impl ScratchBuffers
impl ScratchBuffers
Sourcepub fn new() -> Self
pub fn new() -> Self
Create new scratch buffers with reasonable initial capacity
Allocates buffers with initial capacities optimized for typical COBOL records:
digit_buffer: Stack-allocated (no heap until >32 bytes)byte_buffer: 1 KB initial heap capacitystring_buffer: 512 characters initial heap capacity
These defaults handle most COBOL record layouts without reallocation.
§Examples
use copybook_codec_memory::ScratchBuffers;
let scratch = ScratchBuffers::new();
assert_eq!(scratch.digit_buffer.len(), 0);
assert!(scratch.byte_buffer.capacity() >= 1024);
assert!(scratch.string_buffer.capacity() >= 512);Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Clear all buffers for reuse
Resets buffer lengths to zero without deallocating memory. This is the key operation for buffer reuse - call after each record to prepare for the next processing iteration.
Performance note: This is O(1) and does not touch buffer capacity.
§Examples
use copybook_codec_memory::ScratchBuffers;
let mut scratch = ScratchBuffers::new();
// Use buffers
scratch.digit_buffer.push(5);
scratch.byte_buffer.extend_from_slice(b"data");
scratch.string_buffer.push_str("text");
// Clear for reuse (capacity unchanged)
let byte_capacity = scratch.byte_buffer.capacity();
scratch.clear();
assert_eq!(scratch.digit_buffer.len(), 0);
assert_eq!(scratch.byte_buffer.len(), 0);
assert_eq!(scratch.string_buffer.len(), 0);
assert_eq!(scratch.byte_buffer.capacity(), byte_capacity);Sourcepub fn ensure_byte_capacity(&mut self, capacity: usize)
pub fn ensure_byte_capacity(&mut self, capacity: usize)
Ensure byte buffer has at least the specified capacity
Pre-allocates byte buffer capacity to avoid reallocation during processing. Use this when you know the maximum record size in advance.
Performance optimization: Fast-path optimized for common case where capacity is already sufficient. Growth only occurs when needed.
§Arguments
capacity- Minimum required capacity in bytes
§Examples
use copybook_codec_memory::ScratchBuffers;
let mut scratch = ScratchBuffers::new();
// Pre-allocate for 8 KB records
scratch.ensure_byte_capacity(8192);
assert!(scratch.byte_buffer.capacity() >= 8192);
// No reallocation on subsequent calls with same/lower capacity
scratch.ensure_byte_capacity(4096); // No-op, already sufficientSourcepub fn ensure_string_capacity(&mut self, capacity: usize)
pub fn ensure_string_capacity(&mut self, capacity: usize)
Ensure string buffer has at least the specified capacity
Pre-allocates string buffer capacity to avoid reallocation during text processing. Use this when you know the maximum string field size in advance.
Performance optimization: Fast-path optimized for common case where capacity is already sufficient. Growth only occurs when needed.
§Arguments
capacity- Minimum required capacity in characters (not bytes)
§Examples
use copybook_codec_memory::ScratchBuffers;
let mut scratch = ScratchBuffers::new();
// Pre-allocate for 4096 character fields
scratch.ensure_string_capacity(4096);
assert!(scratch.string_buffer.capacity() >= 4096);
// No reallocation on subsequent calls with same/lower capacity
scratch.ensure_string_capacity(2048); // No-op, already sufficient