Why Rust Powers Our CAD Kernel
Why NeuroCAD chose Rust over C++ for its CAD kernel: memory safety, fearless concurrency, WASM compilation, and a 13-crate modular architecture.
Why Rust Powers Our CAD Kernel
CAD kernels are among the most demanding pieces of software in engineering. They must handle complex geometric algorithms, maintain numerical precision at the limits of floating-point arithmetic, manage large memory-mapped data structures, and do all of this at interactive speeds. For forty years, the answer to “what language do you write a CAD kernel in?” has been C++. ACIS, Parasolid, Open CASCADE --- all C++. We chose Rust, and this article explains why.
The C++ Legacy Problem
C++ is not going away, and the existing kernels built in it represent decades of accumulated engineering value. But C++ carries costs that compound over time:
Memory bugs are the dominant failure mode. Use-after-free, double-free, buffer overflows, dangling pointers --- these account for roughly 70% of critical vulnerabilities in large C++ codebases (per Microsoft and Google’s published analyses). In a CAD kernel, a memory corruption bug does not just crash the application. It can silently corrupt geometry, producing a model that looks correct but has invisible defects. An engineer exports a corrupted STL, sends it to manufacturing, and discovers the problem only when the part fails in service.
Concurrency is fragile. Modern CAD needs parallelism: parallel mesh generation, parallel field evaluation, parallel constraint solving. C++ provides threads and mutexes, but the burden of correctness falls entirely on the programmer. Data races are undefined behavior in C++, and they are notoriously difficult to test for. Most C++ CAD kernels are either single-threaded or use coarse-grained locking that leaves performance on the table.
Build systems and dependency management are painful. A typical C++ CAD kernel depends on Eigen, CGAL, Boost, OpenCascade, and a handful of internal libraries. Managing these dependencies across platforms (Windows, Linux, macOS) with CMake, vcpkg, or Conan is a full-time job. Every dependency update risks breaking the build on at least one platform.
What Rust Offers
Memory Safety Without Garbage Collection
Rust’s ownership system enforces memory safety at compile time. There is no garbage collector, no runtime overhead, and no possibility of use-after-free or data races in safe Rust. The compiler rejects programs that violate ownership rules before they ever run.
For a CAD kernel, this means:
- No silent geometry corruption from dangling pointers.
- No segfaults during long-running Boolean operations.
- No memory leaks from forgotten deallocations in complex graph structures.
The cost is a steeper learning curve for developers accustomed to C++. The borrow checker takes time to internalize. But the investment pays off in dramatically fewer production bugs and much less time spent debugging memory-related crashes.
Fearless Concurrency
Rust’s type system extends memory safety to concurrency. If you hold a mutable reference to data, no other thread can access that data --- the compiler enforces this. The Send and Sync traits explicitly mark which types can cross thread boundaries. Data races are compile-time errors, not runtime mysteries.
This makes it practical to parallelize hot paths with confidence:
- Parallel SDF evaluation across spatial partitions.
- Parallel mesh extraction using marching cubes on independent chunks.
- Parallel constraint solving for independent constraint clusters.
In our testing, adding parallelism to field evaluation yielded near-linear speedup on 8 cores --- something that would have required months of careful auditing in a C++ codebase.
WASM Compilation
Rust compiles to WebAssembly (WASM) with first-class toolchain support via wasm-pack and wasm-bindgen. This is not a secondary target; Rust and WASM were co-developed by Mozilla for exactly this purpose.
For NeuroCAD, WASM compilation means the kernel runs in the browser. No installation, no plugins, no native binaries to distribute. An engineer opens a URL and has a fully functional CAD kernel running at near-native speed in their browser tab. This changes the distribution model fundamentally --- from “download and install” to “click and use.”
The same Rust codebase compiles to native x86_64 for server-side computation (heavy meshing, batch processing) and to WASM for the interactive client. One codebase, two targets, zero code duplication.
The Crate Ecosystem
Rust’s package manager, Cargo, and its ecosystem of crates (libraries) solve the dependency management problem that plagues C++ projects. Dependencies are declared in Cargo.toml, version-resolved automatically, and built reproducibly. Cross-compilation is a flag, not a project.
Key dependencies for a CAD kernel are well-served:
- nalgebra: Production-grade linear algebra with compile-time dimension checking.
- rayon: Data parallelism library that makes parallel iterators trivial.
- thiserror: Ergonomic error type definitions with zero runtime cost.
- tracing: Structured logging and instrumentation.
NeuroCAD’s 13-Crate Architecture
We decomposed the kernel into 13 internal crates organized in a strict dependency DAG:
- kernel_math --- Foundation types: scalars, vectors, angles, bounded domains.
- kernel_params --- Parameter storage with domain validation.
- kernel_graph --- Persistent hypergraph for the operation DAG.
- kernel_primitives --- SDF primitives: sphere, box, cylinder, capsule, torus.
- kernel_field --- Field evaluation, composition operators, e-graph optimization.
- kernel_constraints --- Hard and soft constraint system.
- kernel_surface --- Surface realization from implicit fields.
- kernel_diffusion --- PDE-based field evolution.
- kernel_query --- Query and evaluation systems.
- kernel_meshing --- Mesh extraction (marching cubes and variants).
- kernel_topology --- Topological feature extraction.
- kernel_interop --- Cross-system integration.
- kernel_api --- Public facade that re-exports everything.
This decomposition is enforced by Cargo’s dependency resolution. kernel_math cannot depend on kernel_field --- the compiler will not allow it. Circular dependencies are structurally impossible. Each crate compiles independently, enabling parallel builds and incremental compilation.
The 13-crate structure also enables selective WASM compilation. The browser client needs kernel_api and its transitive dependencies, but not kernel_interop (which handles native file I/O). Cargo’s feature flags let us exclude crates and modules that are irrelevant for the WASM target, keeping the binary small.
Performance
A common concern with Rust is whether it matches C++ performance. For compute-intensive numerical code, the answer is yes. Rust and C++ both compile to LLVM IR and share the same optimizer backend. The generated machine code is comparable.
In our benchmarks:
- SDF evaluation throughput: within 3% of equivalent C++ code (nalgebra vs Eigen).
- Marching cubes mesh extraction: within 5% of the C++ reference implementation.
- Memory usage: typically 5—10% lower due to Rust’s more predictable allocation patterns and lack of hidden copies.
The performance is not the reason to choose Rust. The reason is that you get this performance while also getting memory safety, data-race freedom, and a modern toolchain. The question is not “is Rust faster than C++?” --- it is “can you afford the bugs that C++ permits?”
The Trade-Offs
Rust is not perfect for every situation:
- Ecosystem maturity. The Rust ecosystem for computational geometry is younger than the C++ ecosystem. Libraries like CGAL have no Rust equivalent yet. We implemented our own geometric algorithms where needed, which is more work upfront.
- Learning curve. The borrow checker is genuinely difficult for the first few months. Hiring Rust developers is harder than hiring C++ developers, though the gap is closing.
- Compile times. Rust’s compile times are slower than C++ for equivalent code, primarily due to monomorphization of generics. Incremental compilation and the 13-crate split mitigate this in practice.
- Unsafe code. Performance-critical inner loops sometimes require
unsafeblocks for SIMD intrinsics or unchecked array access. We minimize and audit these blocks, but they exist.
Conclusion
We chose Rust because a CAD kernel is infrastructure that must be correct, fast, and maintainable for decades. Memory safety eliminates the most common and most dangerous class of bugs. Fearless concurrency enables parallelism without fear. WASM compilation enables browser-native deployment. And the crate system keeps the architecture clean as the codebase grows.
The CAD industry’s C++ inertia is real, but it is not a technical argument. It is a legacy argument. For a new kernel built in 2025, Rust is the rational choice.