cstring-array
Safe, zero-copy wrapper for passing string arrays to C FFI (char**
)
This crate provides CStringArray
, a safe abstraction over C's null-terminated string arrays, commonly used for command-line arguments (argv
) and similar purposes.
Features
- Memory-safe: RAII-based lifetime management prevents dangling pointers
- Zero-copy: When constructed from
Vec<CString>
, no re-allocation occurs - C-compatible: Produces valid
char**
pointers with null termination - Ergonomic: Multiple constructors and trait implementations for easy usage
- Well-tested: 98.5%+ test coverage for reliability
- Minimal dependencies: Pure Rust with no external dependencies
- Cross-platform: Works on Linux, macOS, Windows, and more
Quick Start
Add this to your Cargo.toml
:
[]
= "0.1"
Usage
Basic Example
use CStringArray;
use c_char;
let args = vec!;
let array = new.unwrap;
// Safe to pass to C FFI functions expecting char**
let ptr: *const *const c_char = array.as_ptr;
assert_eq!;
Construction Methods
use CStringArray;
use CString;
use TryFrom;
// From Vec<String>
let arr1 = new.unwrap;
// From Vec<CString> (zero-copy)
let cstrings = vec!;
let arr2 = from_cstrings.unwrap;
// Using TryFrom with Vec<&str>
let arr3 = try_from.unwrap;
// Using TryFrom with arrays
let arr4 = try_from.unwrap;
// Using FromIterator (collect)
let arr5: CStringArray = vec!.into_iter.map.collect;
Ergonomic API with Standard Traits
CStringArray
implements standard Rust traits for idiomatic usage:
use CStringArray;
use HashMap;
let arr1 = new.unwrap;
// Clone - independent copies
let arr2 = arr1.clone;
assert_eq!;
// Equality comparison
assert_eq!;
// Hash - use in HashMap/HashSet
let mut map = new;
map.insert;
// Array indexing
assert_eq!;
assert_eq!;
// For loop iteration (borrowed)
for s in &arr1
// For loop iteration (owned - consumes array)
for s in arr2
// Functional programming with iterators
let filtered: CStringArray = vec!
.into_iter
.filter
.map
.collect;
Implemented traits:
Clone
- Deep copy with independent memoryPartialEq
,Eq
- Equality comparisonHash
- Use inHashMap
andHashSet
FromIterator<String>
- Collect fromString
iteratorsFromIterator<CString>
- Collect fromCString
iteratorsIntoIterator
- Owned and borrowed iterationIndex<usize>
- Array-style indexingarr[0]
AsRef<[CString]>
- Generic slice conversion
Real-World Example: Calling C Function
use CStringArray;
use c_char;
extern "C"
Error Handling
use ;
// Interior null bytes are detected
let result = new;
assert!;
// Empty arrays are not allowed
let result = new;
assert!;
Safety Considerations
The pointer returned by CStringArray::as_ptr()
is only valid for the lifetime of the CStringArray
. Ensure the array outlives any C code using the pointer:
use CStringArray;
use c_char;
let array = new.unwrap;
let ptr = array.as_ptr;
call_c_function;
// array must not be dropped before call_c_function returns
Performance
CStringArray
is designed for zero-cost abstractions:
- Zero-copy when constructed from
Vec<CString>
- No re-allocation of strings, only pointer array management
- RAII cleanup without manual memory management
Benchmark Results
Last updated: 2025-10-19 03:04:15 UTC
Operations
Benchmark | Time | Std Dev |
---|---|---|
As Ptr | 0 ns | ±0 ns |
Get | 0 ns | ±0 ns |
Iter | 317 ns | ±0 ns |
Try From Vec Str | 4.94 μs | ±15 ns |
New From Iter | 7.07 μs | ±59 ns |
Construction Comparison
Benchmark | Time | Std Dev |
---|---|---|
Construction Comparison/Try From Vec Str | 5.22 μs | ±26 ns |
Construction Comparison/From Vec New | 5.22 μs | ±10 ns |
Construction Comparison/From Vec String | 5.25 μs | ±19 ns |
From Cstrings Zero Copy
Benchmark | Time | Std Dev |
---|---|---|
From Cstrings Zero Copy/10 | 206 ns | ±1 ns |
From Cstrings Zero Copy/100 | 3.64 μs | ±10 ns |
From Cstrings Zero Copy/1000 | 35.13 μs | ±59 ns |
Large Strings
Benchmark | Time | Std Dev |
---|---|---|
Large Strings/100 | 375 ns | ±1 ns |
Large Strings/1000 | 1.50 μs | ±18 ns |
Large Strings/10000 | 8.03 μs | ±21 ns |
New From Strings
Benchmark | Time | Std Dev |
---|---|---|
New From Strings/10 | 331 ns | ±11 ns |
New From Strings/100 | 4.97 μs | ±11 ns |
New From Strings/1000 | 48.51 μs | ±485 ns |
Sunburst Chart
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice represents the number of statements and the coverage, respectively.
Grid Chart
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Icicle Chart
The top section represents the entire project, proceeding with folders and finally individual files. The size and color of each slice represents the number of statements and the coverage, respectively.
Minimum Supported Rust Version (MSRV)
This crate requires Rust 1.90 or later.
Last updated: 2025-10-19 03:27:56 UTC
Code Statistics
Language | Files | Lines | Code | Comments | Blanks |
---|---|---|---|---|---|
Rust | 17 | 1831 | 1393 | 91 | 347 |
TOML | 5 | 223 | 191 | 6 | 26 |
YAML | 1 | 40 | 28 | 5 | 7 |
JSON | 1 | 0 | 0 | 0 | 0 |
Markdown | 4 | 551 | 0 | 377 | 174 |
Plain Text | 2 | 139 | 0 | 123 | 16 |
Total | 30 | 2784 | 1612 | 602 | 570 |
Test Coverage Breakdown
- Unit Tests: 34 tests (src/tests.rs)
- Integration Tests: 11 tests (tests/integration.rs)
- Property Tests: 12 tests (tests/property_tests.rs)
- Trait Tests: 17 tests (tests/traits.rs)
- Documentation Tests: 20 tests (inline examples)
- Fuzz Targets: 4 targets (libFuzzer-based)
- Total: 94 traditional tests + fuzzing
Security & Quality
- REUSE 3.3 Compliance: 41/41 files (100%)
- Code Coverage: 98.5%+ (Codecov)
- Unsafe Code Validation: Miri testing enabled
- Supply Chain Security: cargo-deny + cargo-audit
- Static Analysis: CodeQL scanning
Related Projects
std::ffi::CString
- Standard library C string typestd::ffi::CStr
- Borrowed C string slice