<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><p>Hi all,</p>
<p>I’ll outline our chosen strategy for the Rust–UNO binding project, explain why we’ve settled on raw FFI against the C UNO API, and show our implementation plan—starting with the very first tasks we’ll tackle.<br><b><br><font size="4">Why We Chose Raw FFI</font></b><br>We have chosen to build our Rust–UNO bindings by using the C UNO API directly through raw FFI instead of using <code><a href="http://cxx.rs">cxx.rs</a></code> or other interop tools. Working with the stable C interface makes our build process easier— avoids the MSVC build errors we saw with recent <code>cxx</code> versions. While this method means writing more manual code to wrap C structs and manage lifetimes, it gives us full control over memory safety and future updates, making maintenance easier down the road.</p><p><br><b><font size="4">Evaluation of <code><a href="http://cxx.rs">cxx.rs</a></code></font></b><br>
During our review, we found three main problems with <code><a href="http://cxx.rs">cxx.rs</a></code>. First, mapping UNO’s complicated inheritance structures and heavy use of templates (like <code>Reference<T></code> and container types) was awkward in Rust’s trait system and <code>cxx</code>’s setup. Second, important C++ features—many types don’t translate cleanly into Rust, leading to fragile wrappers or extra layers. In contrast, Rust’s FFI tools (like <code>bindgen</code>) are well known and reliable.<br><br><font size="4"><b>Implementation Plan</b></font></p><p></p><ol><li><b>Bindgen Generation</b><br>Our very first task is to run <code>bindgen</code> against the primary UNO C headers (e.g., core API headers). This will automatically generate Rust functions, structs, and enum definitions matching the C signatures. We’ll review the generated code, prune any unnecessary items, and ensure the bindings compile cleanly on all target platforms. This gives us a complete low-level foundation—every UNO function and type we need will already exist in Rust, albeit in an unsafe form.<br><br></li><li><b>Safe Wrapper Layer</b><br>UNO’s C API relies on manual reference counting via functions like <code>uno_Reference_addRef</code> and <code>uno_Reference_release</code>. We’ll encapsulate that in Rust smart-pointer types—perhaps <code>UnoRef<T></code>—that call the appropriate add/release functions in their <code>Clone</code> and <code>Drop</code> implementations. This mimics UNO’s <code>Reference<T></code> semantics and ensures that Rust’s ownership rules align with UNO’s lifetime model, all while preserving zero-cost performance.<br><br></li><li><b>Incremental Testing<br></b>Testing happens at every stage. Right after bindgen, we’ll write small build-only tests to check that each raw binding compiles and links. After the safe wrapper layer is in place, we’ll call our <code>embindtest</code> FFI service to verify primitive types (integers, floats, strings) and container types (arrays, sequences) behave correctly. Finally, once smart pointers and ergonomic APIs are ready, we’ll write integration tests against a real UNO service—ensuring end-to-end functionality. This step-by-step validation ensures we catch issues early and keep confidence high as the project grows.</li></ol>Best,<br>Mohamed Ali<br><br><p></p></div></div></div></div></div></div></div></div></div></div></div></div>