
Why I'm Rebuilding TinyXML-2 in Pure, Safe Rust From the Ground Up
Every developer who has worked in game engines (like Cocos2d-x), embedded devices, or legacy C++ enterprise systems has cross paths with TinyXML-2. It is legendary: lightweight, single-header-ish simplicity, fast, and completely predictable.
But as the world migrates toward memory safety and modernized system architectures, modern codebases are left with an awkward choice: wrap the legacy C++ code using unsafe FFI bindings, or adopt giant, heavyweight modern XML specs that blow past binary sizes and memory footprints.
Today, I’m announcing a new project under the Teebot brand: tinyxml2-rs, a ground-up, zero-dependency, pure Rust implementation of the TinyXML-2 API and behavioral specification.
GitHub Repository: github.com/iTeebot/tinyxml2-rs
What it IS vs. What it IS NOT
Let's clear up a few design philosophies right out of the gate:
- Safe, Idiomatic Rust: Built entirely with an arena-based DOM structure. No
unsafein the core engine. Memory safety is guaranteed natively by the compiler. - Behavioral Specification-Driven: We treat TinyXML-2 as an immutable behavioral blueprint. The exact same inputs will produce the exact same outputs, errors, and side effects.
- Drop-in C FFI Layer: It will compile down to
cdylibandstaticlib, providing a transparent, binary-compatible C interface. You will literally be able to swap out the legacy C++ binary for this compiled Rust version in legacy codebases without changing a line of your application code. - NOT a C++ Wrapper: This isn't
bindgentracking down an existing static library. - NOT a line-by-line translation: Transpiled C++ to Rust results in unmaintainable code littered with raw pointers. This is a hand-written, cache-friendly recursive descent parser and DOM.
Core Architectural Highlights
1. The Arena-Based DOM Tree
Standard DOM implementations in Rust are notoriously tricky due to strict ownership rules (every node needs to point to parents, siblings, and children). Using Rc<RefCell<Node>> introduces runtime reference-counting overhead and risks memory leaks via cycles.
Instead, tinyxml2-rs implements a Generational Arena. Every element, text node, and attribute resides inside a single contiguous vector allocation. Node handles are simply lightweight, type-safe generational IDs. This means:
- Cache-friendly, sequential memory layout.
- O(1) lookups and mutations.
- Blazing fast multi-threaded traversals without pointer indirection.
2. Hand-Written Recursive Descent Parser
To match the unique quirks and optimized error-handling of TinyXML-2, we bypassed modern macro-heavy parser combinators (like nom) in favor of a clean, lightweight, state-driven recursive descent layout. This ensures zero external dependencies and keeps binary sizes remarkably small, making it ideal for microcontrollers and WASM targets.
Current Project Roadmap
We are currently pushing through Phase 1 (Foundation). The architectural scaffolding is live:
- [x] Project scaffolding & Cargo Workspace layout
- [x] Generational Arena DOM skeleton
- [ ] Error types & Entity escaping mapping (In progress)
- [ ] Hand-written Lexer & Recursive Descent Parser (Planned)
- [ ] C FFI Export Interoperability (Planned)
Join the Journey / Contribute
This project is fully open-source under the MIT license. If you love memory-safe systems engineering, playing around with cache-friendly data structures, or writing robust compiler/parser tools, I would love your feedback, eyes, and contributions!
- Star the Repo: github.com/iTeebot/tinyxml2-rs
- Let me know in the comments: Would you use a pure-Rust drop-in replacement for TinyXML-2 in your production systems?