From 88109a2270a187187e77f4e3cb2b95336170060c Mon Sep 17 00:00:00 2001 From: RAprogramm Date: Sun, 19 Oct 2025 07:27:41 +0700 Subject: [PATCH] #5 docs: add practical usage examples - Add examples/basic.rs - basic CStringArray usage - Add examples/command_line.rs - FFI with command-line args - Add examples/env_vars.rs - environment variables handling - Add examples/zero_copy.rs - zero-copy construction demo - Update REUSE.toml to include examples directory Examples demonstrate: - Creating arrays from Vec - Zero-copy construction from Vec - FFI interoperability with C functions - Safe iteration and element access - Real-world use cases (CLI args, env vars) - Automatic memory management - Performance considerations All examples: - Compile without warnings - Run successfully - Include comprehensive comments - Follow REUSE 3.3 specification - Demonstrate best practices Usage: cargo run --example basic cargo run --example command_line -- arg1 arg2 cargo run --example env_vars cargo run --example zero_copy --- REUSE.toml | 6 ++++ examples/basic.rs | 51 ++++++++++++++++++++++++++++++ examples/command_line.rs | 63 +++++++++++++++++++++++++++++++++++++ examples/env_vars.rs | 67 +++++++++++++++++++++++++++++++++++++++ examples/zero_copy.rs | 68 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 255 insertions(+) create mode 100644 examples/basic.rs create mode 100644 examples/command_line.rs create mode 100644 examples/env_vars.rs create mode 100644 examples/zero_copy.rs diff --git a/REUSE.toml b/REUSE.toml index 2f06851..c71c866 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -14,3 +14,9 @@ path = "README.md" precedence = "aggregate" SPDX-FileCopyrightText = "2025 RAprogramm " SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "examples/*.rs" +precedence = "aggregate" +SPDX-FileCopyrightText = "2025 RAprogramm " +SPDX-License-Identifier = "MIT" diff --git a/examples/basic.rs b/examples/basic.rs new file mode 100644 index 0000000..8fc16e8 --- /dev/null +++ b/examples/basic.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-License-Identifier: MIT + +//! Basic usage example of CStringArray. +//! +//! This example demonstrates: +//! - Creating a CStringArray from Vec +//! - 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(""); + 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."); +} diff --git a/examples/command_line.rs b/examples/command_line.rs new file mode 100644 index 0000000..3676288 --- /dev/null +++ b/examples/command_line.rs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2025 RAprogramm +// 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(""); + println!(" argv[{}] = \"{}\"", i, arg); + } + } + } +} + +fn main() { + println!("Command-Line Argument Example\n"); + + let args: Vec = std::env::args().collect(); + + if args.len() < 2 { + println!("Usage: {} ...", 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), + } + } +} diff --git a/examples/env_vars.rs b/examples/env_vars.rs new file mode 100644 index 0000000..25ba97f --- /dev/null +++ b/examples/env_vars.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2025 RAprogramm +// 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 = 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 = 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."); +} diff --git a/examples/zero_copy.rs b/examples/zero_copy.rs new file mode 100644 index 0000000..eab057c --- /dev/null +++ b/examples/zero_copy.rs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2025 RAprogramm +// SPDX-License-Identifier: MIT + +//! Zero-copy construction example. +//! +//! This example demonstrates: +//! - Creating CStringArray from Vec (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 -> Array (move ownership)"); + + println!("\nUse zero-copy when:"); + println!(" - You already have Vec"); + println!(" - Performance is critical"); + println!(" - Working with large arrays"); + println!(" - Avoiding redundant allocations"); + + println!("\nDemonstrating with larger dataset:"); + let large_cstrings: Vec = (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."); +}