|
1 | 1 | # `flatdata` Schema Language |
2 | 2 |
|
3 | | -## Imports |
4 | | - |
5 | | -Flatdata schemas can be split across multiple files using import statements. |
6 | | -An import pulls in all definitions (structs, enums, constants, archives) from |
7 | | -another schema file, making them available for use in the importing file. |
8 | | - |
9 | | -```cpp |
10 | | -import "path/to/types.flatdata"; |
11 | | -``` |
12 | | - |
13 | | -Import statements must appear at the top of the file, before any namespace or |
14 | | -type definitions. |
15 | | - |
16 | | -### Path Resolution |
17 | | - |
18 | | -Import paths are resolved **relative to the file** containing the import |
19 | | -statement. Both same-directory and nested-directory paths are supported: |
20 | | - |
21 | | -```cpp |
22 | | -import "types.flatdata"; // same directory |
23 | | -import "sub/geo_types.flatdata"; // subdirectory |
24 | | -import "../shared/common.flatdata"; // parent directory |
25 | | -``` |
26 | | - |
27 | | -### Diamond Imports |
28 | | - |
29 | | -A file may be imported by multiple other files without conflict. For example, |
30 | | -if both `a.flatdata` and `b.flatdata` import `common.flatdata`, and |
31 | | -`main.flatdata` imports both `a.flatdata` and `b.flatdata`, all definitions |
32 | | -from `common.flatdata` are deduplicated automatically. |
33 | | - |
34 | | -### Cyclic Imports |
35 | | - |
36 | | -Cyclic imports are supported. For example, a parent archive schema can import |
37 | | -a child schema that imports the parent back (e.g. for reference annotations): |
38 | | - |
39 | | -```cpp |
40 | | -// parent.flatdata |
41 | | -import "child.flatdata"; |
42 | | -namespace m { |
43 | | - archive Parent { |
44 | | - items : vector< Item >; |
45 | | - } |
46 | | -} |
47 | | - |
48 | | -// child.flatdata |
49 | | -import "parent.flatdata"; |
50 | | -namespace m { |
51 | | - struct Item { |
52 | | - value : u64 : 64; |
53 | | - } |
54 | | -} |
55 | | -``` |
56 | | -
|
57 | | -### Generated Code Behavior |
58 | | -
|
59 | | -The generator uses **separate compilation** for C++ and Rust: |
60 | | -
|
61 | | -- Only types defined in the **root file** (the file passed to the generator) |
62 | | - are emitted in the generated output. |
63 | | -- Imported types are expected to be generated separately from their own root |
64 | | - file. |
65 | | -- The generator emits appropriate include/import directives to reference the |
66 | | - separately generated code. |
67 | | -
|
68 | | -For **C++**, the generator emits `#include` directives for each imported file |
69 | | -(with the `.flatdata` extension replaced by `.h`). |
70 | | -
|
71 | | -For **Rust**, the generator emits `pub use super::...::module::namespace::*;` |
72 | | -re-exports so that types from imported modules are accessible in the correct |
73 | | -namespace. |
74 | | -
|
75 | | -For **Python**, **Dot**, and **Flatdata** output, all types (both local and |
76 | | -imported) are emitted monolithically since these generators produce |
77 | | -self-contained output. |
78 | | -
|
79 | | -### Example |
80 | | -
|
81 | | -Given the following project structure: |
82 | | -
|
83 | | -``` |
84 | | -schema/ |
85 | | -├── types.flatdata |
86 | | -└── main.flatdata |
87 | | -``` |
88 | | -
|
89 | | -```cpp |
90 | | -// types.flatdata |
91 | | -namespace n { |
92 | | - struct Point { |
93 | | - x : u32 : 32; |
94 | | - y : u32 : 32; |
95 | | - } |
96 | | -} |
97 | | -``` |
98 | | - |
99 | | -```cpp |
100 | | -// main.flatdata |
101 | | -import "types.flatdata"; |
102 | | -namespace app { |
103 | | - archive Locations { |
104 | | - points : vector< .n.Point >; |
105 | | - } |
106 | | -} |
107 | | -``` |
108 | | -
|
109 | | -Generate each file separately: |
110 | | -
|
111 | | -```sh |
112 | | -flatdata-generator -s schema/types.flatdata -g cpp -O schema/types.h |
113 | | -flatdata-generator -s schema/main.flatdata -g cpp -O schema/main.h |
114 | | -``` |
115 | | - |
116 | | -The generated `main.h` will contain `#include "types.h"` and only emit the |
117 | | -`app::Locations` archive, referencing `n::Point` from the included header. |
118 | | - |
119 | | -### Rust Project Setup |
120 | | - |
121 | | -The generated Rust code uses `pub use super::...::module::namespace::*;` |
122 | | -re-exports to connect imported types. This requires that each generated file |
123 | | -lives in its own module, and that sibling schemas share a common parent module. |
124 | | - |
125 | | -For the same schema above (`main.flatdata` importing `types.flatdata`): |
126 | | - |
127 | | -``` |
128 | | -my_crate/ |
129 | | -├── build.rs |
130 | | -└── src/ |
131 | | - ├── lib.rs |
132 | | - └── schema/ |
133 | | - ├── mod.rs |
134 | | - ├── types.rs |
135 | | - └── main_schema.rs |
136 | | -``` |
137 | | - |
138 | | -```rust |
139 | | -// build.rs |
140 | | -fn main() { |
141 | | - // Generate all .flatdata files into OUT_DIR/schema/ |
142 | | - flatdata::generate("schema/", &std::env::var("OUT_DIR").unwrap()) |
143 | | - .expect("generator failed"); |
144 | | -} |
145 | | -``` |
146 | | - |
147 | | -```rust |
148 | | -// src/lib.rs |
149 | | -pub mod schema; |
150 | | -``` |
151 | | - |
152 | | -```rust |
153 | | -// src/schema/mod.rs |
154 | | -pub mod types; |
155 | | -pub mod main_schema; |
156 | | -``` |
157 | | - |
158 | | -```rust |
159 | | -// src/schema/types.rs |
160 | | -include!(concat!(env!("OUT_DIR"), "/schema/types.rs")); |
161 | | -``` |
162 | | - |
163 | | -```rust |
164 | | -// src/schema/main_schema.rs |
165 | | -include!(concat!(env!("OUT_DIR"), "/schema/main.rs")); |
166 | | -``` |
167 | | - |
168 | | -The key requirement is that each generated `.rs` file is wrapped in its own |
169 | | -module, and all imported schemas are siblings in the same parent module. The |
170 | | -`super::` re-exports navigate from the namespace module up to the parent module |
171 | | -where sibling schema modules are accessible. |
172 | | - |
173 | 3 | ## Basic Types |
174 | 4 |
|
175 | 5 | Flatdata supports the following primitive types: |
@@ -488,3 +318,99 @@ Retrieving all edges is now as easy as this: |
488 | 318 | ```cpp |
489 | 319 | edges.slice(nodes[i].edges_range) |
490 | 320 | ``` |
| 321 | + |
| 322 | +## Imports |
| 323 | + |
| 324 | +Schemas can be split across multiple files using import statements. |
| 325 | +An import pulls in all definitions (structs, enums, constants, archives) from |
| 326 | +another file, making them available for use in the importing file. |
| 327 | + |
| 328 | +```cpp |
| 329 | +import "path/to/types.flatdata"; |
| 330 | +``` |
| 331 | + |
| 332 | +Import statements must appear at the top of the file, before any namespace or |
| 333 | +type definitions. |
| 334 | + |
| 335 | +### Path Resolution |
| 336 | + |
| 337 | +Import paths are resolved **relative to the file** containing the import |
| 338 | +statement: |
| 339 | + |
| 340 | +```cpp |
| 341 | +import "types.flatdata"; // same directory |
| 342 | +import "sub/geo_types.flatdata"; // subdirectory |
| 343 | +import "../shared/common.flatdata"; // parent directory |
| 344 | +``` |
| 345 | + |
| 346 | +### Diamond and Cyclic Imports |
| 347 | + |
| 348 | +Diamond imports (the same file imported via multiple paths) are deduplicated |
| 349 | +automatically. Cyclic imports are also supported — a parent archive schema can |
| 350 | +import a child schema that imports the parent back. |
| 351 | + |
| 352 | +### Generated Code |
| 353 | + |
| 354 | +For **C++** and **Rust**, the generator uses separate compilation: only types |
| 355 | +from the root file are emitted, with include/import directives referencing |
| 356 | +the separately generated imported files. Each `.flatdata` file must be |
| 357 | +generated individually. |
| 358 | + |
| 359 | +For **Python**, **Dot**, and **Flatdata** output, all types are emitted |
| 360 | +monolithically. |
| 361 | + |
| 362 | +### Example |
| 363 | + |
| 364 | +``` |
| 365 | +schema/ |
| 366 | +├── types.flatdata |
| 367 | +└── main.flatdata |
| 368 | +``` |
| 369 | + |
| 370 | +```cpp |
| 371 | +// types.flatdata |
| 372 | +namespace geo { |
| 373 | + struct Point { |
| 374 | + x : u32 : 32; |
| 375 | + y : u32 : 32; |
| 376 | + } |
| 377 | +} |
| 378 | +``` |
| 379 | +
|
| 380 | +```cpp |
| 381 | +// main.flatdata |
| 382 | +import "types.flatdata"; |
| 383 | +namespace app { |
| 384 | + archive Locations { |
| 385 | + points : vector< .geo.Point >; |
| 386 | + } |
| 387 | +} |
| 388 | +``` |
| 389 | + |
| 390 | +Generate each file separately: |
| 391 | + |
| 392 | +```sh |
| 393 | +flatdata-generator -s schema/types.flatdata -g cpp -O schema/types.h |
| 394 | +flatdata-generator -s schema/main.flatdata -g cpp -O schema/main.h |
| 395 | +``` |
| 396 | + |
| 397 | +The generated `main.h` will contain `#include "types.h"` and only define the |
| 398 | +`app::Locations` archive. |
| 399 | + |
| 400 | +### Rust Project Setup |
| 401 | + |
| 402 | +Each generated Rust file must live in its own module, with all imported schemas |
| 403 | +as siblings under a common parent module: |
| 404 | + |
| 405 | +``` |
| 406 | +my_crate/ |
| 407 | +├── build.rs |
| 408 | +└── src/ |
| 409 | + └── schema/ |
| 410 | + ├── mod.rs // pub mod types; pub mod main_schema; |
| 411 | + ├── types.rs // include!(concat!(env!("OUT_DIR"), "/schema/types.rs")); |
| 412 | + └── main_schema.rs // include!(concat!(env!("OUT_DIR"), "/schema/main.rs")); |
| 413 | +``` |
| 414 | + |
| 415 | +The generated code uses `pub use super::...::module::namespace::*;` re-exports |
| 416 | +to wire imported types through the module hierarchy. |
0 commit comments