Skip to content
//! Shared encoding helpers for the hand-rolled FFI.
//!
//! Structured data (schemas, generated rows, config text) crosses the JS/Rust
//! boundary as UTF-8 byte buffers — there is no serde/JSON here. We use two
//! ASCII control characters as separators because they essentially never appear
//! in real grid data: Unit Separator between fields and Record Separator between
//! records. The JS side strips any stray occurrences from sampled values.

/// Field separator (ASCII Unit Separator).
pub const US: char = '\u{1f}';
/// Record separator (ASCII Record Separator).
pub const RS: char = '\u{1e}';

/// Pull a variable-length byte buffer out of an FFI import.
///
/// The convention: the import writes up to `cap` bytes at `ptr` and returns the
/// number of bytes it *wanted* to write. If that exceeds the buffer we grow and
/// call again, so the importer never has to guess a size up front.
pub fn pull(mut write_into: impl FnMut(*mut u8, usize) -> usize) -> Vec<u8> {
    let mut cap = 4096usize;
    loop {
        let mut buf = vec![0u8; cap];
        let needed = write_into(buf.as_mut_ptr(), cap);
        if needed <= cap {
            buf.truncate(needed);
            return buf;
        }
        cap = needed;
    }
}