Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ path = "README.md"
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 RAprogramm <andrey.rozanov.vl@gmail.com>"
SPDX-License-Identifier = "MIT"

[[annotations]]
path = "examples/*.rs"
precedence = "aggregate"
SPDX-FileCopyrightText = "2025 RAprogramm <andrey.rozanov.vl@gmail.com>"
SPDX-License-Identifier = "MIT"
51 changes: 51 additions & 0 deletions examples/basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
// SPDX-License-Identifier: MIT

//! Basic usage example of CStringArray.
//!
//! This example demonstrates:
//! - Creating a CStringArray from Vec<String>
//! - Converting to C-compatible char** pointer
//! - Safe iteration over elements
//! - Automatic memory cleanup

use cstring_array::CStringArray;

fn main() {
println!("Basic CStringArray Usage Example\n");

let args = vec![
"my-program".to_string(),
"--verbose".to_string(),
"input.txt".to_string(),
"output.txt".to_string(),
];

println!("Creating CStringArray from {} strings:", args.len());
for (i, arg) in args.iter().enumerate() {
println!(" [{}] {}", i, arg);
}

let array = CStringArray::new(args).expect("Failed to create CStringArray");

println!("\nArray properties:");
println!(" Length: {}", array.len());
println!(" Empty: {}", array.is_empty());
println!(" Pointer: {:p}", array.as_ptr());

println!("\nIterating over elements:");
for (i, cstr) in array.iter().enumerate() {
let s = cstr.to_str().unwrap_or("<invalid utf-8>");
println!(" [{}] {}", i, s);
}

println!("\nAccessing individual elements:");
if let Some(first) = array.get(0) {
println!(" First: {}", first.to_str().unwrap());
}
if let Some(last) = array.get(array.len() - 1) {
println!(" Last: {}", last.to_str().unwrap());
}

println!("\nArray will be automatically freed when it goes out of scope.");
}
63 changes: 63 additions & 0 deletions examples/command_line.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
// SPDX-License-Identifier: MIT

//! Command-line argument handling example.
//!
//! This example demonstrates:
//! - Processing command-line arguments
//! - Creating CStringArray for FFI calls
//! - Simulating a C function that takes char** argv
//! - Real-world usage pattern

use std::ffi::{c_char, c_int, CStr};

use cstring_array::CStringArray;

#[allow(improper_ctypes_definitions)]
extern "C" fn print_args(argc: c_int, argv: *const *const c_char) {
println!("C function received {} arguments:", argc);
for i in 0..argc {
unsafe {
let arg_ptr = *argv.offset(i as isize);
if !arg_ptr.is_null() {
let cstr = CStr::from_ptr(arg_ptr);
let arg = cstr.to_str().unwrap_or("<invalid utf-8>");
println!(" argv[{}] = \"{}\"", i, arg);
}
}
}
}

fn main() {
println!("Command-Line Argument Example\n");

let args: Vec<String> = std::env::args().collect();

if args.len() < 2 {
println!("Usage: {} <arg1> <arg2> ...", args[0]);
println!("\nExample:");
println!(" cargo run --example command_line -- hello world");
return;
}

println!("Rust received {} arguments:", args.len());
for (i, arg) in args.iter().enumerate() {
println!(" [{}] {}", i, arg);
}

println!("\nPassing to C function via FFI:");
let array = CStringArray::new(args).expect("Failed to create CStringArray");

print_args(array.len() as c_int, array.as_ptr());

println!("\nDemonstrating command parsing:");
for (i, arg) in array.iter().enumerate() {
let arg_str = arg.to_str().unwrap();
match arg_str {
s if s.starts_with("--") => println!(" Option: {}", s),
s if s.starts_with('-') => println!(" Flag: {}", s),
s if i == 0 => println!(" Program: {}", s),
s => println!(" Argument: {}", s),
}
}
}
67 changes: 67 additions & 0 deletions examples/env_vars.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
// SPDX-License-Identifier: MIT

//! Environment variables example.
//!
//! This example demonstrates:
//! - Creating CStringArray from environment variables
//! - Formatting strings for C-style environment (KEY=VALUE)
//! - Passing environment to child processes via FFI
//! - Filtering and transforming data

use cstring_array::CStringArray;

fn main() {
println!("Environment Variables Example\n");

let env_vars: Vec<String> = std::env::vars()
.map(|(key, value)| format!("{}={}", key, value))
.collect();

println!("Total environment variables: {}\n", env_vars.len());

println!("First 10 environment variables:");
for (i, var) in env_vars.iter().take(10).enumerate() {
println!(" [{}] {}", i, var);
}

println!("\nCreating CStringArray from environment...");
let env_array = CStringArray::new(env_vars).expect("Failed to create CStringArray");

println!("Array created successfully:");
println!(" Length: {}", env_array.len());
println!(" Pointer: {:p}", env_array.as_ptr());

println!("\nSearching for PATH variable:");
for env in env_array.iter() {
let env_str = env.to_str().unwrap();
if env_str.starts_with("PATH=") {
println!(" Found: {}", env_str);
break;
}
}

println!("\nFiltering variables with prefix:");
let prefix = "CARGO_";
println!("Variables starting with '{}':", prefix);
for env in env_array.iter() {
let env_str = env.to_str().unwrap();
if env_str.starts_with(prefix) {
println!(" {}", env_str);
}
}

println!("\nCreating filtered environment:");
let filtered: Vec<String> = std::env::vars()
.filter(|(key, _)| key.starts_with("CARGO_") || key == "PATH" || key == "HOME")
.map(|(key, value)| format!("{}={}", key, value))
.collect();

let filtered_env = CStringArray::new(filtered).expect("Failed to create filtered array");
println!("Filtered environment has {} variables:", filtered_env.len());
for env in filtered_env.iter() {
println!(" {}", env.to_str().unwrap());
}

println!("\nThis array can be passed to execve() or similar C functions.");
}
68 changes: 68 additions & 0 deletions examples/zero_copy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: 2025 RAprogramm <andrey.rozanov.vl@gmail.com>
// SPDX-License-Identifier: MIT

//! Zero-copy construction example.
//!
//! This example demonstrates:
//! - Creating CStringArray from Vec<CString> (zero-copy)
//! - Performance benefits of zero-copy construction
//! - When to use from_cstrings() vs new()
//! - Memory efficiency

use std::ffi::CString;

use cstring_array::CStringArray;

fn main() {
println!("Zero-Copy Construction Example\n");

println!("Method 1: Regular construction (allocates CString internally)");
let strings = vec![
"first".to_string(),
"second".to_string(),
"third".to_string(),
];
let array1 = CStringArray::new(strings).expect("Failed to create array");
println!(" Created array with {} elements", array1.len());

println!("\nMethod 2: Zero-copy construction (no re-allocation)");
let cstrings = vec![
CString::new("first").unwrap(),
CString::new("second").unwrap(),
CString::new("third").unwrap(),
];

println!(" Pre-allocated {} CStrings", cstrings.len());
let array2 = CStringArray::from_cstrings(cstrings).expect("Failed to create array");
println!(" Created array with {} elements (zero-copy)", array2.len());

println!("\nPerformance comparison:");
println!(" Regular: String -> CString (internal allocation)");
println!(" Zero-copy: Vec<CString> -> Array (move ownership)");

println!("\nUse zero-copy when:");
println!(" - You already have Vec<CString>");
println!(" - Performance is critical");
println!(" - Working with large arrays");
println!(" - Avoiding redundant allocations");

println!("\nDemonstrating with larger dataset:");
let large_cstrings: Vec<CString> = (0..1000)
.map(|i| CString::new(format!("string_{}", i)).unwrap())
.collect();

println!(" Created {} CStrings", large_cstrings.len());
let large_array = CStringArray::from_cstrings(large_cstrings).expect("Failed to create array");
println!(" Zero-copy array length: {}", large_array.len());
println!(" First element: {}", large_array.get(0).unwrap().to_str().unwrap());
println!(
" Last element: {}",
large_array
.get(large_array.len() - 1)
.unwrap()
.to_str()
.unwrap()
);

println!("\nMemory is automatically freed when array goes out of scope.");
}