cstring_array/lib.rs
1// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
2//
3// SPDX-License-Identifier: MIT
4
5//! Safe, zero-copy wrapper for passing string arrays to C FFI (`char**`)
6//!
7//! This crate provides [`CStringArray`], a safe abstraction over C's
8//! null-terminated string arrays, commonly used for command-line arguments and
9//! similar purposes.
10//!
11//! # Features
12//!
13//! - **Memory-safe**: RAII-based lifetime management prevents dangling pointers
14//! - **Zero-copy**: When constructed from `Vec<CString>`, no re-allocation
15//! occurs
16//! - **C-compatible**: Produces valid `char**` pointers with null termination
17//! - **Ergonomic**: Multiple constructors and trait implementations for easy
18//! usage
19//! - **Well-tested**: Comprehensive test coverage for reliability
20//!
21//! # Example
22//!
23//! ```
24//! use std::ffi::c_char;
25//!
26//! use cstring_array::CStringArray;
27//!
28//! let args = vec![
29//! "program".to_string(),
30//! "--verbose".to_string(),
31//! "file.txt".to_string(),
32//! ];
33//! let array = CStringArray::new(args).unwrap();
34//!
35//! // Safe to pass to C FFI functions expecting char**
36//! let ptr: *const *const c_char = array.as_ptr();
37//! assert_eq!(array.len(), 3);
38//! ```
39//!
40//! # Creating Arrays
41//!
42//! Multiple ways to construct a `CStringArray`:
43//!
44//! ```
45//! use std::{convert::TryFrom, ffi::CString};
46//!
47//! use cstring_array::CStringArray;
48//!
49//! // From Vec<String>
50//! let arr1 = CStringArray::new(vec!["foo".to_string(), "bar".to_string()]).unwrap();
51//!
52//! // From Vec<CString> (zero-copy)
53//! let cstrings = vec![CString::new("foo").unwrap(), CString::new("bar").unwrap()];
54//! let arr2 = CStringArray::from_cstrings(cstrings).unwrap();
55//!
56//! // Using TryFrom with Vec<&str>
57//! let arr3 = CStringArray::try_from(vec!["foo", "bar"]).unwrap();
58//!
59//! // Using TryFrom with arrays
60//! let arr4 = CStringArray::try_from(["foo", "bar"]).unwrap();
61//!
62//! // Using FromIterator (collect)
63//! let arr5: CStringArray = vec!["a", "b", "c"].into_iter().map(String::from).collect();
64//! ```
65//!
66//! # Trait Implementations
67//!
68//! `CStringArray` implements many standard Rust traits for ergonomic usage:
69//!
70//! ```
71//! use std::collections::HashMap;
72//!
73//! use cstring_array::CStringArray;
74//!
75//! let arr1 = CStringArray::new(vec!["a".to_string(), "b".to_string()]).unwrap();
76//!
77//! // Clone
78//! let arr2 = arr1.clone();
79//! assert_eq!(arr1, arr2);
80//!
81//! // Equality
82//! assert_eq!(arr1, arr2);
83//!
84//! // Hash (use in HashMap)
85//! let mut map = HashMap::new();
86//! map.insert(arr1.clone(), "value");
87//!
88//! // Indexing
89//! assert_eq!(arr1[0].to_str().unwrap(), "a");
90//! assert_eq!(arr1[1].to_str().unwrap(), "b");
91//!
92//! // Iteration (borrowed)
93//! for s in &arr1 {
94//! println!("{}", s.to_str().unwrap());
95//! }
96//!
97//! // Iteration (owned)
98//! for s in arr2 {
99//! println!("{}", s.to_str().unwrap());
100//! }
101//!
102//! // AsRef conversion
103//! fn process_strings(strings: &[std::ffi::CString]) {
104//! println!("Processing {} strings", strings.len());
105//! }
106//! process_strings(arr1.as_ref());
107//! ```
108//!
109//! # Safety Considerations
110//!
111//! The pointer returned by [`CStringArray::as_ptr`] is only valid for the
112//! lifetime of the `CStringArray`. Ensure the array outlives any C code using
113//! the pointer:
114//!
115//! ```
116//! use std::ffi::c_char;
117//!
118//! use cstring_array::CStringArray;
119//!
120//! fn call_c_function(argv: *const *const c_char, argc: i32) {
121//! // ... FFI call ...
122//! }
123//!
124//! let array = CStringArray::new(vec!["arg1".to_string(), "arg2".to_string()]).unwrap();
125//! let ptr = array.as_ptr();
126//! call_c_function(ptr, array.len() as i32);
127//! // array must not be dropped before call_c_function returns
128//! ```
129
130mod array;
131mod error;
132mod traits;
133
134#[cfg(test)]
135mod tests;
136
137pub use array::CStringArray;
138pub use error::CStringArrayError;