Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1b34cf3
copied my orginal repo to this repo and pasted it
shashu8660 Mar 23, 2026
0b701d6
making adjustment in CmakeList
shashu8660 Mar 23, 2026
1880aeb
imporved makefile so any system can use
shashu8660 Mar 23, 2026
3c1bf63
new updated README
shashu8660 Mar 23, 2026
c0e1bc8
Merge branch 'main' into add-example1
shashu8660 Mar 23, 2026
a6168dd
change in readme
shashu8660 Mar 23, 2026
6b5c003
Merge branch 'main' into add-example1
shashu8660 Mar 25, 2026
d445af0
Added run.sh script for CI
shashu8660 Mar 25, 2026
e73f59d
update the run.sh
shashu8660 Mar 26, 2026
4867149
Make run.sh executable for CI
shashu8660 Mar 26, 2026
621f669
added rust code for string-interop-interact
shashu8660 Mar 28, 2026
1f70b4f
added the working main.cpp for my example
shashu8660 Mar 28, 2026
13fce15
add remaning files
shashu8660 Mar 28, 2026
0fab25d
added run.sh
shashu8660 Mar 28, 2026
7f45c81
added gitignore and minor changes too
shashu8660 Mar 28, 2026
52fe44a
added detailed readme for my example
shashu8660 Mar 28, 2026
3687b64
Remove unrelated example
shashu8660 Mar 28, 2026
d6dbacb
Remove unrelated example
shashu8660 Mar 28, 2026
db9413a
Update heading level for Move section in README
shashu8660 Mar 28, 2026
aab852f
Update README with string interop summary
shashu8660 Mar 28, 2026
75ea1c7
changed unsafe to raw pointer and format change
shashu8660 Mar 28, 2026
5beef37
Add safety documentation for unsafe FFI functions
shashu8660 Mar 28, 2026
659a200
Fix safety docs for unsafe FFI functions
shashu8660 Mar 28, 2026
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
17 changes: 17 additions & 0 deletions examples/string-interop-interact/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Rust build output
target/
Cargo.lock

# Binary output
main
*.o
*.a

# macOS
.DS_Store

# CMake (if used)
build/
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
153 changes: 153 additions & 0 deletions examples/string-interop-interact/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
- Problem Name: string-interop-interact
- Start Date: 28-02-2026
- Problem Statement PR:

## Summary
[summary]: #summary

This example demonstrates safe and interactive string interoperability between Rust and C++.

C++ and Rust use different string representations (`std::string` and `String`), which cannot be shared directly across the FFI boundary. To solve this, the example uses C-style strings (`const char*`) as a common interface.

The example showcases a multi-step interaction:
- Rust initiates a prompt to the user
- C++ handles user input
- The input is passed to Rust for processing
- Rust returns a new string back to C++
- C++ prints the result and ensures proper memory deallocation

This highlights key concepts such as ownership transfer, memory safety, and bidirectional communication between Rust and C++.

### Example Code
[example-code]: #example-code

This example highlights ownership transfer across the FFI boundary using three key concepts: **Move**, **Forget**, and **Own**.

---

### 🔹 Move (Rust → C++)

```rust
CString::new(response).unwrap().into_raw();
```
- Converts a Rust String into a C-compatible string
- into_raw() transfers ownership to C++
- Rust no longer manages this memory

### 🔹 Forget (Rust does not free automatically)

- Ownership has been transferred, Rust will not drop this memory

### 🔹 Own + Free (C++ -> Rust)

```cpp
char* response = process_name(name.c_str());
free_string(response);
```
```rust
let _ = CString::from_raw(ptr);
```

- C++ receives ownership of the string
- C++ must explicitly call free_string
- Rust reconstructs and safely frees the memory

### What might go wrong?

- If free_string is not called → memory leak
- If freed twice → double free crash
- If freed by C++ directly (e.g., delete/free) → undefined behavior

## How to Build and Run

### Requirements

- Rust (with `cargo`)
- A C++ compiler (`g++` or `clang++`)

---

### Build and Run

From the example directory:

```bash
./run.sh

## Example Output

```text
Rust: What is your name?
shashank
C++ received: Welcome, shashank!
```

### How it Work (Flow)

This example demonstrates a multi-step interaction between C++, Rust, and the user

- Step-by-step flow

1. **C++ calls Rust to initiate interaction**

```cpp
ask_name();
```

- Rust print: What is your name?

2. **User provides input (handled by C++)**

```cpp
std::getline(std::cin, name);
```
- C++ reads user input into a std::string

3. **C++ sends the string to Rust**

```cpp
process_name(name.c_str());
```
- std::string is converted to const char*
- This crosses the FFI boundary

4. **Rust processes the input**

```rust
let response = format!("Welcome, {}!", name_str);
```

- Rust safely converts the input using CStr
- Generates a new response string

5. **Rust returns a new string to C++**

```rust
CString::new(response).unwrap().into_raw()
```
- Ownership is transferred to C++
- Rust no longer manages this memory

6. **C++ receives and prints the result

```cpp
std::cout << response << std::endl;
```

7. **C++ frees memory using Rust**

```cpp
free_string(response);
```

- Rust reconstructs the string and safely frees it

**Summary**
```text
C++ → Rust (prompt)
User → C++ (input)
C++ → Rust (process)
Rust → C++ (response)
C++ → Rust (free memory)
```

43 changes: 43 additions & 0 deletions examples/string-interop-interact/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// This example demonstrates safe string interoperability between C++ and Rust,
// including ownership transfer and proper memory deallocation across the FFI boundary.

#include <iostream> // For input/output (std::cout, std::cin)
#include <string> // For using std::string

// Declare Rust functions using C ABI so C++ can call them
extern "C" {
void ask_name(); // Rust function to print prompt
char* process_name(const char* name); // Rust function that processes input and returns a string
void free_string(char* ptr); // Rust function to free allocated memory
}

int main() {
// Step 1: Ask Rust to prompt user
ask_name();
// Calls Rust function which prints: "What is your name?"

// Step 2: User input handled in C++
std::string name;
// std::string stores user input safely in C++

std::getline(std::cin, name);
// Read full line from terminal input into 'name'

// Step 3: Send to Rust
char* response = process_name(name.c_str());
// Convert std::string → const char* using .c_str()
// Pass pointer to Rust (FFI boundary)
// Rust returns a new allocated string (ownership transferred to C++)

// Step 4: Print response
std::cout << "C++ received: " << response << std::endl;
// Print the string returned from Rust

// Step 5: Free memory
free_string(response);
// IMPORTANT: call Rust function to free memory
// Prevents memory leak since Rust allocated it

return 0;
// Program ends
}
33 changes: 33 additions & 0 deletions examples/string-interop-interact/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@


#!/usr/bin/env bash
# This script builds and runs the string interop example (C++ ↔ Rust)

# Exit immediately if a command fails, treat unset variables as errors
set -euo pipefail

# Use default C++ compiler if not provided
if [ -z "${CXX:-}" ]; then
echo "CXX not set, using default compiler: c++"
CXX=c++
fi

# Ensure script runs from its own directory
cd "$(dirname "$0")"

echo "Building Rust library..."

# Step 1: Build Rust static library
cd rust-lib
cargo build --release
cd ..

echo "Compiling C++ code..."

# Step 2: Compile C++ and link Rust static library
$CXX main.cpp rust-lib/target/release/librust_lib.a -o main

echo "Running program..."

# Step 3: Run executable
./main
8 changes: 8 additions & 0 deletions examples/string-interop-interact/rust-lib/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "rust-lib"
version = "0.1.0"
edition = "2024"


[lib]
crate-type = ["staticlib"]
40 changes: 40 additions & 0 deletions examples/string-interop-interact/rust-lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use std::ffi::{CStr, CString}; // Import CString (for owned C strings) and CStr (for borrowed C strings)
use std::os::raw::c_char; // Import C-compatible char type

// Step 1: Rust prints prompt
#[unsafe(no_mangle)] // Prevent Rust from changing the function name (needed for C++ linkage)
pub extern "C" fn ask_name() {
// Expose function using C ABI so C++ can call it
println!("Rust: What is your name?"); // Print prompt from Rust side
}

/// # Safety
// Step 2: Rust processes input from C++
#[unsafe(no_mangle)] // Keep function name stable for FFI
pub unsafe extern "C" fn process_name(name: *const c_char) -> *mut c_char {
// `name` is a raw pointer from C++ (const char*)

let c_str = unsafe { CStr::from_ptr(name) };
// Convert raw pointer into a safe Rust CStr reference (unsafe because Rust trusts C++)

let name_str = c_str.to_str().unwrap();
// Convert CStr to Rust &str (UTF-8 string slice)

let response = format!("Welcome, {}!", name_str);
// Create a new Rust String with formatted message

CString::new(response).unwrap().into_raw()
// Convert Rust String → CString → raw pointer
// `into_raw()` transfers ownership to C++ (Rust will NOT free it automatically)
}

/// # Safety
// Step 3: Free memory
#[unsafe(no_mangle)] // Required for C++ to call this function
pub unsafe extern "C" fn free_string(ptr: *mut c_char) {
unsafe {
let _ = CString::from_raw(ptr);
// Reconstruct CString from raw pointer
// When this goes out of scope, Rust automatically frees the memory
}
}