Add example: passing Rust structs to C++ via opaque pointers#46
Add example: passing Rust structs to C++ via opaque pointers#46thebabalola wants to merge 4 commits intorustfoundation:mainfrom
Conversation
Demonstrates the create/use/release pattern for passing heap-allocated Rust data to C++ through FFI. C++ holds an opaque pointer to a Rust Person struct and uses extern "C" functions to create, inspect, and free it. Includes a Drop implementation that prints when cleanup runs. Adapted from: https://github.com/wisonye/rust-ffi-demo Related: rustfoundation#13
|
Hi @teor2345 ... I opened this PR to adapt a real-world FFI example from https://github.com/wisonye/rust-ffi-demo. Also, i'm planning to add a string return pattern next (get_person_info / release_get_person_info), but happy to hear if there's a direction you think would be more useful. |
Add a Location struct (city, country) as a field on Person. C++ passes city and country as plain strings to create_person; Rust builds the Location internally and owns it alongside the Person. This demonstrates nested struct ownership across the FFI boundary — C++ never sees Location directly, and both structs are freed together when release_person is called.
|
Thanks for this PR, but we're only reviewing one PR per person at the moment. I've already see your PR #38, so I'm going to mark this one as draft. We can decide what to do with it once your other PR has finished. |
Add get_person_info and release_get_person_info to demonstrate the string return pattern across the FFI boundary. Rust allocates a CString from the person's data and hands the raw pointer to C++. C++ reads the string, then calls release_get_person_info to let Rust free it. C++ must never call free() or delete on it directly. This is a common real-world pattern when Rust needs to return text data to a foreign caller that doesn't know how Rust manages memory.
Document the key interop differences inline: - why to_string_lossy is used instead of unwrap (C strings may not be UTF-8) - why Box::from_raw pairs with Box::into_raw (correct allocator; C++ free() would be UB) - module-level note on drop order and memory ownership Add two new tests: - test_gender_variants: verifies all three gender codes (0/1/2+) produce a valid pointer - test_info_contains_location: verifies get_person_info output includes both city and country
|
To round up this PR, I added inline comments documenting the key interop differences , why to_string_lossy instead of unwrap (C strings aren't guaranteed UTF-8), why Box::from_raw pairs with Box::into_raw (C++'s free() would be UB), and a module-level note on drop order and memory ownership. Also added two new tests: one for all three gender variants, one verifying get_person_info includes both city and country. with 5 passing tests. The example is complete on my end, ready for your review whenever you have time. |
This builds on the basic math example in #38 by demonstrating a more realistic FFI pattern , passing heap-allocated Rust structs to C++ using opaque pointers.
The example includes:
Personstruct with aGenderenum, exposed viaextern "C"functionscreate_personto allocate,print_personto inspect, andrelease_personto freeDropimplementation that prints when cleanup runs, so you can verify Rust properly frees the memoryrun.shshell script that builds and links everythingSince C++ never sees inside the Rust struct , and only holds an opaque pointer. This is the standard pattern for passing complex Rust data to C++ without exposing internal layout.
Adapted from: https://github.com/wisonye/rust-ffi-demo
Related: #13