Rust API Reference

Full API documentation is available on docs.rs.

JSONTools

The main builder struct for all JSON operations. Uses the owned-self builder pattern -- all configuration methods consume and return Self for chaining.

Construction

#![allow(unused)]
fn main() {
use json_tools_rs::JSONTools;

let tools = JSONTools::new();
}

JSONTools implements Default, Debug, and Clone.

Operation Modes

Exactly one mode must be set before calling .execute().

MethodDescription
.flatten()Flatten nested JSON into separator-delimited keys
.unflatten()Reconstruct nested JSON from flat, separator-delimited keys
.normal()Apply transformations without changing the nesting structure
#![allow(unused)]
fn main() {
use json_tools_rs::{JSONTools, JsonOutput};

// Flatten
let result = JSONTools::new()
    .flatten()
    .execute(r#"{"a": {"b": 1}}"#)?;

// Unflatten
let result = JSONTools::new()
    .unflatten()
    .execute(r#"{"a.b": 1}"#)?;

// Normal mode -- transformations only
let result = JSONTools::new()
    .normal()
    .lowercase_keys(true)
    .auto_convert_types(true)
    .execute(r#"{"Name": "John", "Age": "30"}"#)?;
}

Configuration Methods

All methods consume self and return Self for chaining. Marked #[must_use].

MethodTypeDefaultDescription
.separator(sep)impl Into<String>"."Key separator for flatten/unflatten
.lowercase_keys(flag)boolfalseConvert all keys to lowercase
.remove_empty_strings(flag)boolfalseFilter out "" values
.remove_nulls(flag)boolfalseFilter out null values
.remove_empty_objects(flag)boolfalseFilter out {} values
.remove_empty_arrays(flag)boolfalseFilter out [] values
.key_replacement(find, replace)impl Into<String>, impl Into<String>--Add a key replacement regex pattern
.value_replacement(find, replace)impl Into<String>, impl Into<String>--Add a value replacement regex pattern
.handle_key_collision(flag)boolfalseCollect colliding keys into arrays
.auto_convert_types(flag)boolfalseAuto-convert string values to native types
.parallel_threshold(n)usize100Min batch size for parallel processing
.num_threads(n)Option<usize>None (CPU count)Thread count for parallelism
.nested_parallel_threshold(n)usize100Min keys/items for intra-document parallelism
.max_array_index(n)usize100_000Max array index during unflattening (DoS protection)

Note: .separator() panics if given an empty string. Defaults for parallel_threshold, nested_parallel_threshold, num_threads, and max_array_index can be overridden via environment variables (see Performance Tuning).

Execution

#![allow(unused)]
fn main() {
pub fn execute<'a, T>(&self, json_input: T) -> Result<JsonOutput, JsonToolsError>
where
    T: Into<JsonInput<'a>>,
}

Accepts any type that implements Into<JsonInput>:

Rust TypeJsonInput Variant
&strSingle(Cow::Borrowed)
&StringSingle(Cow::Borrowed)
&[&str]Multiple (borrowing)
Vec<&str>MultipleOwned
Vec<String>MultipleOwned
&[String]MultipleOwned

Errors: Returns Err(JsonToolsError) if no mode is set, JSON is invalid, or processing fails.

Full Example

#![allow(unused)]
fn main() {
use json_tools_rs::{JSONTools, JsonOutput};

let tools = JSONTools::new()
    .flatten()
    .separator("::")
    .lowercase_keys(true)
    .remove_nulls(true)
    .remove_empty_strings(true)
    .key_replacement("^user_", "")
    .auto_convert_types(true)
    .parallel_threshold(50)
    .num_threads(Some(4));

// Single document
let result = tools.execute(r#"{"User_Name": "Alice", "User_Age": "30"}"#)?;
match result {
    JsonOutput::Single(s) => println!("{}", s),
    JsonOutput::Multiple(_) => unreachable!(),
}

// Batch processing
let batch: Vec<String> = (0..1000)
    .map(|i| format!(r#"{{"id": "{}"}}"#, i))
    .collect();
let results = tools.execute(batch)?;
match results {
    JsonOutput::Multiple(v) => println!("Processed {} items", v.len()),
    JsonOutput::Single(_) => unreachable!(),
}
}

JsonInput

Input enum for execute(). You rarely construct this directly -- the From implementations handle conversion automatically.

#![allow(unused)]
fn main() {
pub enum JsonInput<'a> {
    /// Single JSON string (zero-copy via Cow)
    Single(Cow<'a, str>),
    /// Multiple JSON strings (borrowing)
    Multiple(&'a [&'a str]),
    /// Multiple JSON strings (owned or mixed)
    MultipleOwned(Vec<Cow<'a, str>>),
}
}

From Implementations

Source TypeVariant
&strSingle(Cow::Borrowed)
&StringSingle(Cow::Borrowed)
&[&str]Multiple
Vec<&str>MultipleOwned
Vec<String>MultipleOwned
&[String]MultipleOwned
#![allow(unused)]
fn main() {
use json_tools_rs::{JSONTools, JsonOutput};

let tools = JSONTools::new().flatten();

// All of these work transparently:
let _ = tools.execute(r#"{"a": 1}"#);                      // &str
let s = String::from(r#"{"a": 1}"#);
let _ = tools.execute(&s);                                  // &String
let batch = vec![r#"{"a": 1}"#, r#"{"b": 2}"#];
let _ = tools.execute(batch);                               // Vec<&str>
let owned: Vec<String> = vec![r#"{"a": 1}"#.into()];
let _ = tools.execute(owned);                               // Vec<String>
}

JsonOutput

Output enum from execute().

#![allow(unused)]
fn main() {
pub enum JsonOutput {
    /// Single JSON result string
    Single(String),
    /// Multiple JSON result strings (batch)
    Multiple(Vec<String>),
}
}

Methods

MethodReturnsDescription
.into_single()StringExtract single result. Panics on Multiple.
.into_multiple()Vec<String>Extract batch results. Panics on Single.
.try_into_single()Result<String, JsonToolsError>Non-panicking single extraction
.try_into_multiple()Result<Vec<String>, JsonToolsError>Non-panicking batch extraction
.into_vec()Vec<String>Always returns a Vec (wraps Single in a one-element vec)
#![allow(unused)]
fn main() {
use json_tools_rs::{JSONTools, JsonOutput};

let result = JSONTools::new().flatten().execute(r#"{"a": {"b": 1}}"#)?;

// Pattern matching (recommended)
match result {
    JsonOutput::Single(s) => println!("Single: {}", s),
    JsonOutput::Multiple(v) => println!("Batch of {}", v.len()),
}

// Direct extraction (panics on wrong variant)
let s = JSONTools::new().flatten().execute(r#"{"a": 1}"#)?.into_single();

// Safe extraction (returns Result)
let s = JSONTools::new().flatten().execute(r#"{"a": 1}"#)?.try_into_single()?;

// Always-vec (useful for uniform handling)
let v = JSONTools::new().flatten().execute(r#"{"a": 1}"#)?.into_vec();
assert_eq!(v.len(), 1);
}

JsonToolsError

Comprehensive error enum with machine-readable error codes (E001-E008), human-readable messages, and actionable suggestions.

#![allow(unused)]
fn main() {
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum JsonToolsError {
    JsonParseError { .. },           // E001
    RegexError { .. },               // E002
    InvalidReplacementPattern { .. }, // E003
    InvalidJsonStructure { .. },     // E004
    ConfigurationError { .. },       // E005
    BatchProcessingError { .. },     // E006
    InputValidationError { .. },     // E007
    SerializationError { .. },       // E008
}
}

Methods

MethodReturnsDescription
.error_code()&'static strMachine-readable code: "E001" through "E008"

Error Handling Example

#![allow(unused)]
fn main() {
use json_tools_rs::{JSONTools, JsonToolsError};

let result = JSONTools::new().flatten().execute("invalid json");

match result {
    Ok(output) => { /* success */ }
    Err(e) => {
        // Machine-readable error code
        match e.error_code() {
            "E001" => eprintln!("JSON parsing error: {}", e),
            "E005" => eprintln!("Configuration error: {}", e),
            "E006" => eprintln!("Batch error: {}", e),
            code => eprintln!("[{}] {}", code, e),
        }

        // Pattern matching for specific handling
        match &e {
            JsonToolsError::JsonParseError { message, suggestion, .. } => {
                eprintln!("Parse failed: {}", message);
                eprintln!("Try: {}", suggestion);
            }
            JsonToolsError::BatchProcessingError { index, source, .. } => {
                eprintln!("Item {} failed: {}", index, source);
            }
            _ => eprintln!("{}", e),
        }
    }
}
}

Auto-Conversions

JsonToolsError implements From for common error types:

#![allow(unused)]
fn main() {
// These conversions happen automatically in ? chains:
impl From<json_parser::JsonError> for JsonToolsError { .. }  // -> E001
impl From<regex::Error> for JsonToolsError { .. }            // -> E002
}

See Error Codes for the full error reference.

ProcessingConfig

Low-level configuration struct used internally by JSONTools. You can construct it directly for advanced use cases, but the JSONTools builder is the recommended interface.

#![allow(unused)]
fn main() {
pub struct ProcessingConfig {
    pub separator: String,
    pub lowercase_keys: bool,
    pub filtering: FilteringConfig,
    pub collision: CollisionConfig,
    pub replacements: ReplacementConfig,
    pub auto_convert_types: bool,
    pub parallel_threshold: usize,
    pub num_threads: Option<usize>,
    pub nested_parallel_threshold: usize,
    pub max_array_index: usize,
}
}

Builder Methods

#![allow(unused)]
fn main() {
use json_tools_rs::ProcessingConfig;

let config = ProcessingConfig::new()
    .separator("::")
    .lowercase_keys(true)
    .filtering(FilteringConfig::new().set_remove_nulls(true))
    .collision(CollisionConfig::new().handle_collisions(true))
    .replacements(
        ReplacementConfig::new()
            .add_key_replacement("^old_", "new_")
    );
}

FilteringConfig

Configuration for value filtering, stored internally as a bitmask for single-instruction checks on the hot path.

#![allow(unused)]
fn main() {
pub struct FilteringConfig { /* bitmask */ }
}

Builder Methods

All methods consume and return Self.

MethodDescription
.set_remove_empty_strings(bool)Filter "" values
.set_remove_nulls(bool)Filter null values
.set_remove_empty_objects(bool)Filter {} values
.set_remove_empty_arrays(bool)Filter [] values

Query Methods

MethodReturnsDescription
.remove_empty_strings()boolIs empty string filtering enabled?
.remove_nulls()boolIs null filtering enabled?
.remove_empty_objects()boolIs empty object filtering enabled?
.remove_empty_arrays()boolIs empty array filtering enabled?
.has_any_filter()boolIs any filter enabled?
#![allow(unused)]
fn main() {
use json_tools_rs::FilteringConfig;

let filtering = FilteringConfig::new()
    .set_remove_nulls(true)
    .set_remove_empty_strings(true);

assert!(filtering.has_any_filter());
assert!(filtering.remove_nulls());
assert!(!filtering.remove_empty_objects());
}

CollisionConfig

Configuration for key collision handling.

#![allow(unused)]
fn main() {
pub struct CollisionConfig {
    pub handle_collisions: bool,
}
}

Builder Methods

MethodDescription
.handle_collisions(bool)Enable/disable collision handling

Query Methods

MethodReturnsDescription
.has_collision_handling()boolIs collision handling enabled?
#![allow(unused)]
fn main() {
use json_tools_rs::CollisionConfig;

let collision = CollisionConfig::new().handle_collisions(true);
assert!(collision.has_collision_handling());
}

ReplacementConfig

Configuration for key and value replacement patterns. Uses SmallVec<[(String, String); 2]> internally to avoid heap allocation for the common case of 0-2 replacements.

#![allow(unused)]
fn main() {
pub struct ReplacementConfig {
    pub key_replacements: SmallVec<[(String, String); 2]>,
    pub value_replacements: SmallVec<[(String, String); 2]>,
}
}

Builder Methods

MethodDescription
.add_key_replacement(find, replace)Add a key replacement regex pattern
.add_value_replacement(find, replace)Add a value replacement regex pattern

Query Methods

MethodReturnsDescription
.has_key_replacements()boolAre any key replacements configured?
.has_value_replacements()boolAre any value replacements configured?
#![allow(unused)]
fn main() {
use json_tools_rs::ReplacementConfig;

let replacements = ReplacementConfig::new()
    .add_key_replacement("^user_", "")
    .add_value_replacement("@old\\.com", "@new.com");

assert!(replacements.has_key_replacements());
assert!(replacements.has_value_replacements());
}