# Data Streaming Research: FlatBuffers for DESI Explorer This directory aggregates research on using **FlatBuffers** as the wire protocol between the Rust/axum API (`api/`) and the Odin + raylib GUI (`gui/`). The goal is to provide implementation-ready knowledge — not to build anything yet. ## Context DESI Explorer currently serves placeholder JSON from a Rust/axum API and renders procedurally generated points in an Odin + raylib client. The two halves are **disconnected**: the API has stubbed `/api/v1/catalogs` and `/api/v1/objects` endpoints returning JSON; the GUI has hand-written mirror structs in `gui/src/data.odin` with stub `get_catalogs()` / `get_catalog_objects()` procedures. Real DESI catalog data (galaxies, quasars, stars with `ra`, `dec`, `redshift`) will eventually stream server → client. FlatBuffers is attractive here because: - **Zero-copy reads**: the GUI can access fields directly from the network buffer with no parsing or allocation — critical when rendering tens of thousands of points per frame. - **Schema-versioned**: forward/backward compatibility as the DESI catalog schema evolves across releases (edr → dr1 → dr2 → ...). - **Cross-language**: Rust and Odin can both generate code from the same `.fbs` schema. - **Compact binary**: smaller payloads than JSON over the wire. ## Research Documents | # | Document | Purpose | |---|----------|---------| | 01 | [architecture.md](01-architecture.md) | Current system architecture and where FlatBuffers fits in | | 02 | [flatbuffers-overview.md](02-flatbuffers-overview.md) | What FlatBuffers is, how the format works internally | | 03 | [rust-integration.md](03-rust-integration.md) | Rust/axum API integration: crates, build tooling, codegen pipelines | | 04 | [odin-client-integration.md](04-odin-client-integration.md) | Odin GUI integration: FFI, flatcc, OdinArrow, HTTP/WebSocket clients | | 05 | [streaming-protocols.md](05-streaming-protocols.md) | WebSocket + HTTP + framing options for streaming FlatBuffers | | 06 | [schema-design.md](06-schema-design.md) | DESI-specific schema proposal and evolution rules | | 07 | [alternatives.md](07-alternatives.md) | Cap'n Proto, Protocol Buffers, MessagePack, Apache Arrow comparison | | 08 | [testing-strategies.md](08-testing-strategies.md) | Unit, integration, cross-language, fuzz, and conformance testing | | 09 | [pain-points.md](09-pain-points.md) | Cons, gotchas, and pain points to watch out for | | 10 | [performance-benchmarks.md](10-performance-benchmarks.md) | Published benchmarks (serialize/deserialize/size) and analysis | ## TL;DR Recommendation **FlatBuffers is a strong fit** for the DESI Explorer streaming use case, specifically for the *server → client* bulk data path (catalog objects). The zero-copy read model matches the render loop perfectly: the GUI ingests a binary blob over WebSocket or HTTP, verifies it once, and reads `ra`/`dec`/`redshift` directly from the buffer each frame without allocations. **Key caveats to weigh before committing:** 1. **Odin has no first-party FlatBuffers binding.** You must go through the C ABI (via `flatcc` headers + Odin `foreign` blocks) or hand-roll a minimal reader. [OdinArrow](https://github.com/TimeLord/OdinArrow) already hand-rolls a FlatBuffers encoder/decoder for the Arrow IPC header — proof the pattern is viable in pure Odin. 2. **Serialization is more complex than JSON/protobuf.** The builder API builds buffers back-to-front (children before parents). This is a server-side cost you pay once per batch, not per client — acceptable. 3. **Not self-describing.** Binary buffers are opaque without the schema. The API and GUI must share the same `.fbs` file and version discipline. Add file identifiers and keep both sides in lockstep via a shared schema checkout. 4. **FlatBuffers is larger on the wire than protobuf** (estimated 20-50% larger on small messages due to vtable overhead), but ~30-100x faster on reads. For a read-heavy renderer this trade is worth it. 5. **WASM considerations.** The Web GUI build (Emscripten/WASM) uses raylib via Odin. If FlatBuffers keep-alive buffers share memory between the Odin side and the JS/WebSocket glue, you need to manage Emscripten memory carefully. This is the least-researched area of this report. ## Immediate Next Steps (when you're ready to implement) ```mermaid flowchart TD A["Prototype schema
catalog.fbs: Catalog · CatalogObject · ServerMessage union"] B["Generate Rust code
flatc --rust → api/build.rs · serve WS via axum"] C["Prototype the Odin reader
flatcc FFI · pure-Odin · OdinArrow"] D["Static fixture files
flatc --binary → committed .bin"] E["Cross-language tests
Rust + Odin read the same fixtures identically"] A --> B --> C --> D --> E ``` 1. **Prototype schema first.** Write `catalog.fbs` covering `Catalog`, `CatalogObject`, and a `ServerMessage` union (handshake / catalog list / chunk of objects / end). 2. **Generate Rust code** via `flatc --rust` in an `api/build.rs` (see `03-rust-integration.md`) and serve over WebSocket using axum's `ws` module (tower-http CORS + `axum::extract::ws`). 3. **Prototype the Odin reader.** Pick one of three paths (FFI to `flatcc`, pure-Odin reader port, or OdinArrow reuse) and read a FlatBuffer produced by the Rust side to prove interop. A single `CatalogObject` with `ra`, `dec`, `redshift` is enough to validate the entire pipeline. 4. **Static fixture files.** Generate `.fbs` → FlatBuffer binaries once with `flatc --binary`, check them into the repo, and write a cross-language test that both Rust and Odin read the same fixture identically. This is the backbone of your integration test story (see `08-testing-strategies.md`).