synta 0.1.4

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
# API Reference

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [Command-Line Interface]#command-line-interface
  - [Synopsis]#synopsis
  - [Options]#options
    - [`-o, --output <file>`]#-o-output
    - [`--output-dir <dir>`]#-output-dir
    - [`--lang <language>`]#-lang
    - [`--c`]#-c
    - [`--check-imports`]#-check-imports
    - [`--crate-imports`]#-crate-imports
    - [`--super-imports`]#-super-imports
    - [`--module-prefix <prefix>`]#-module-prefix
    - [`--use-core`]#-use-core
    - [`--header-path <path>`]#-header-path
    - [`--with-helpers`]#-with-helpers
    - [`--arena`]#-arena
    - [`--impl <header>`]#-impl
    - [`--emit <artifacts>`]#-emit
    - [`--cmake`]#-cmake
    - [`--meson`]#-meson
    - [`--shared`]#-shared
    - [`--synta-root <dir>`]#-synta-root
  - [Examples]#examples
- [Library API -- Rust generation]#library-api-rust-generation
  - [`parse`]#parse
  - [`generate`]#generate
  - [`generate_with_config`]#generatewithconfig
  - [`CodeGenConfig`]#codegenconfig
  - [`StringTypeMode`]#stringtypemode
  - [`DeriveMode`]#derivemode
- [Library API -- C generation]#library-api-c-generation
  - [`generate_c`]#generate_c
  - [`generate_c_with_config`]#generatecwith_config
  - [`CCodeGenConfig`]#ccodegenconfig
  - [`generate_c_impl`]#generatecimpl
  - [`CImplConfig`]#cimplconfig
- [AST types]#ast-types
  - [`Module`]#module
  - [`Definition`]#definition
  - [`ParseError`]#parseerror
- [See Also]#see-also

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Complete reference for the synta-codegen library and command-line interface.

---

## Command-Line Interface

### Synopsis

```
synta-codegen [OPTIONS] <input.asn1> [extra.asn1 ...]
```

### Options

#### `-o, --output <file>`

Write output to `file`. Default: stdout.

#### `--output-dir <dir>`

Write one generated file per input module into `dir`. Files are written in
topological dependency order (base modules first). Cannot be combined with `-o`.

#### `--lang <language>`

Target language. Accepted values: `rust` (default), `c`.

#### `--c`

Shorthand for `--lang c`.

#### `--check-imports`

Parse all input files and check for circular module import cycles. If a cycle is
detected, report it and exit with a non-zero status. No code is generated.

#### `--crate-imports`

Rust only. Emit `use crate::module::Type` statements for imported ASN.1 types.

#### `--super-imports`

Rust only. Emit `use super::module::Type` statements for imported ASN.1 types.

#### `--module-prefix <prefix>`

Rust only. Emit `use <prefix>::module::Type` statements. The prefix is used
verbatim followed by `::`.

#### `--use-core`

Rust only. Replace `std::` paths with `core::` equivalents in generated code
(no_std environments).

#### `--header-path <path>`

C only. Path written into the `#include "..."` directive for `synta.h` in the
generated header. Default: `"synta.h"`.

#### `--with-helpers`

C only. Generate `_init`, `_validate`, and `_print` inline helper functions for
every type.

#### `--arena`

C only. Generate the `SyntaArena` type and `_decode_arena()` function prototypes
(in the header) or bodies (in the implementation).

#### `--impl <header>`

C only. Single-file mode: generate a `.c` implementation file instead of a `.h`
header file. The argument specifies the name of the corresponding header file,
which is placed in the generated `#include "..."` directive. Not compatible with
`--output-dir` and multiple input files; use `--emit` instead.

#### `--emit <artifacts>`

C only. Used with `--output-dir`. Controls which artifacts are written per
module. Accepted values:

- `header` (default) — write only `.h` header files.
- `impl` — write only `.c` implementation files.
- `both` — write both `.h` and `.c` files for each module.

When `--cmake` or `--meson` is combined with `--output-dir`, `--emit` defaults
to `both` automatically so the generated build file's source references are
satisfied.

#### `--cmake`

Generate a `CMakeLists.txt` build file. Without `--output-dir`, writes only the
build file (to stdout or `-o`). With `--output-dir`, also generates C source
files (equivalent to `--emit both`) so the build file's `.c` references are
immediately satisfied.

#### `--meson`

Generate a `meson.build` file. Without `--output-dir`, writes only the build
file (to stdout or `-o`). With `--output-dir`, also generates C source files
(equivalent to `--emit both`).

#### `--shared`

Used with `--cmake` or `--meson`. Configure the generated build file to build a
shared library instead of a static library.

#### `--synta-root <dir>`

Used with `--cmake` or `--meson`. Embed `dir` as the hard-coded path to the synta
installation in the generated build file.

### Examples

**Rust: single file**

```sh
synta-codegen schema.asn1 -o src/generated.rs
synta-codegen schema.asn1 --crate-imports -o src/generated.rs
synta-codegen schema.asn1 --super-imports -o src/generated.rs
synta-codegen schema.asn1 --module-prefix my_lib -o src/generated.rs
synta-codegen schema.asn1 --use-core -o src/generated.rs
cat schema.asn1 | synta-codegen > generated.rs
```

**Rust: multi-file output**

```sh
synta-codegen base.asn1 user.asn1 --crate-imports --output-dir src/gen/
synta-codegen base.asn1 user.asn1 --check-imports
```

**C: header and implementation**

```sh
synta-codegen schema.asn1 --c -o generated.h
synta-codegen schema.asn1 --impl generated.h -o generated.c
synta-codegen schema.asn1 --c --with-helpers -o generated.h
synta-codegen schema.asn1 --c --arena -o generated.h
synta-codegen schema.asn1 --impl generated.h --arena -o generated.c
synta-codegen schema.asn1 --c --header-path "../../include/synta.h" -o generated.h
```

**C: multi-file output**

```sh
synta-codegen base.asn1 user.asn1 --c --output-dir ./generated/
synta-codegen base.asn1 user.asn1 --c --emit both --output-dir ./generated/
synta-codegen base.asn1 user.asn1 --check-imports
```

**Build system files**

```sh
synta-codegen schema.asn1 --cmake -o CMakeLists.txt
synta-codegen schema.asn1 --meson -o meson.build
synta-codegen base.asn1 user.asn1 --cmake --output-dir ./generated/
synta-codegen schema.asn1 --cmake --synta-root /opt/synta -o CMakeLists.txt
synta-codegen schema.asn1 --cmake --shared -o CMakeLists.txt
```

---

## Library API -- Rust generation

### `parse`

```rust
pub fn parse(input: &str) -> Result<Module, ParseError>
```

Parse an ASN.1 module definition from `input`. Returns the parsed AST on success
or a `ParseError` with line and column information on failure. Accepts exactly one
module per call.

### `generate`

```rust
pub fn generate(module: &Module) -> Result<String, std::fmt::Error>
```

Generate Rust source code for `module` using default configuration: no import
statements emitted, `std::` paths used.

### `generate_with_config`

```rust
pub fn generate_with_config(
    module: &Module,
    config: CodeGenConfig,
) -> Result<String, std::fmt::Error>
```

Generate Rust source code applying the settings in `config`.

### `CodeGenConfig`

```rust
pub struct CodeGenConfig {
    pub module_path_prefix: Option<String>,
    pub use_core: bool,
    pub skip_imported_types: std::collections::HashSet<String>,
    pub imported_type_lifetimes: std::collections::HashMap<String, String>,
    pub string_type_mode: StringTypeMode,
    pub any_as_raw_der: bool,
    pub derive_mode: DeriveMode,
}
```

- `module_path_prefix` -- when `Some(prefix)`, emit `use prefix::module::Type` for ASN.1 IMPORTS; `None` annotates imports as comments only.
- `use_core` -- when `true`, emits `core::` instead of `std::` in generated paths.
- `skip_imported_types` -- set of imported type names not declared locally (assumed to come from external modules).
- `imported_type_lifetimes` -- map from imported type name to lifetime string (e.g. `"'a"`) for zero-copy types.
- `string_type_mode` -- controls whether `OCTET STRING`, `BIT STRING`, and string types emit owned or zero-copy borrowed forms. See [`StringTypeMode`]#stringtypemode.
- `any_as_raw_der` -- when `true`, `ANY` and `ANY DEFINED BY` fields are emitted as `RawDer<'a>` instead of `Element<'a>`.
- `derive_mode` -- controls how derive macros are gated. See [`DeriveMode`]#derivemode.

Convenience constructors set `module_path_prefix` and leave all other fields at their defaults:

```rust
use synta_codegen::CodeGenConfig;

let config = CodeGenConfig::with_crate_imports();   // use crate::module::Type
let config = CodeGenConfig::with_super_imports();   // use super::module::Type
let config = CodeGenConfig::with_custom_prefix("my_lib"); // use my_lib::module::Type
```

### `StringTypeMode`

```rust
pub enum StringTypeMode {
    Owned,    // default
    Borrowed,
}
```

- `Owned` -- emit heap-allocating owned types (`OctetString`, `BitString`, `Utf8String`, etc.). Default.
- `Borrowed` -- emit zero-copy borrowed types (`OctetStringRef<'a>`, `BitStringRef<'a>`, `Utf8StringRef<'a>`, etc.).

### `DeriveMode`

```rust
pub enum DeriveMode {
    FeatureGated,      // default
    Always,
    Custom(String),
}
```

Controls how derive macros (`Asn1Sequence`, `Asn1Choice`, `Asn1Set`) and their helper
attributes are emitted.

- `FeatureGated` (default) -- wraps every annotation in `#[cfg_attr(feature = "derive", …)]`. The consuming crate must declare `[features] derive = ["dep:synta-derive"]` in its `Cargo.toml`.
- `Always` -- emits `#[derive(Asn1Sequence)]` unconditionally with no feature gate. Use this when the consuming crate always depends on `synta-derive`.
- `Custom(name)` -- uses a caller-supplied feature name instead of `"derive"`.

**Example:**

```rust
use synta_codegen::{CodeGenConfig, DeriveMode};

// Default: feature-gated (consuming crate needs a "derive" feature)
let config = CodeGenConfig::default();

// Always emit derive attributes unconditionally
let config = CodeGenConfig {
    derive_mode: DeriveMode::Always,
    ..CodeGenConfig::with_crate_imports()
};

// Use a custom feature name
let config = CodeGenConfig {
    derive_mode: DeriveMode::Custom("asn1-derive".to_string()),
    ..CodeGenConfig::with_crate_imports()
};
```

---

## Library API -- C generation

### `generate_c`

```rust
pub fn generate_c(module: &Module) -> Result<String, Box<dyn std::error::Error>>
```

Generate a C header file from `module` using default configuration.

### `generate_c_with_config`

```rust
pub fn generate_c_with_config(
    module: &Module,
    config: CCodeGenConfig,
) -> Result<String, Box<dyn std::error::Error>>
```

Generate a C header file applying the settings in `config`.

### `CCodeGenConfig`

```rust
pub struct CCodeGenConfig {
    pub synta_header_path: Option<String>,
    pub generate_helpers: bool,
    pub arena_mode: bool,
}
```

- `synta_header_path` -- path placed in `#include "..."` for `synta.h`. Default: `"synta.h"`.
- `generate_helpers` -- emit `_init`, `_validate`, and `_print` inline helpers. Default: `false`.
- `arena_mode` -- emit `SyntaArena` type and `_decode_arena()` prototypes. Default: `false`.

Builder methods are available for convenience:

```rust,ignore
// Set custom synta.h include path
CCodeGenConfig::with_header_path("../../include/synta.h")

// Enable _init / _validate / _print helpers
config.with_helpers()

// Enable SyntaArena + _decode_arena() prototypes
config.with_arena()
```

**Example:**

```rust,ignore
use synta_codegen::{parse, generate_c_with_config, CCodeGenConfig};

let module = parse(schema)?;
let config = CCodeGenConfig::with_header_path("synta/synta.h")
    .with_helpers()
    .with_arena();
let header = generate_c_with_config(&module, config)?;
```

### `generate_c_impl`

```rust
pub fn generate_c_impl(
    module: &Module,
    config: CImplConfig,
) -> Result<String, Box<dyn std::error::Error>>
```

Generate a C implementation file (`.c`) from `module`.

### `CImplConfig`

```rust
pub struct CImplConfig {
    pub header_file: String,
    pub arena_mode: bool,
}
```

- `header_file` -- name of the corresponding header file, placed in the generated
  `#include "..."` directive.
- `arena_mode` -- generate `_decode_arena()` function bodies. Default: `false`.

**Example:**

```rust
use synta_codegen::{parse, generate_c_impl, CImplConfig};

let module = parse(schema)?;
let impl_code = generate_c_impl(&module, CImplConfig {
    header_file: "types.h".into(),
    arena_mode: false,
})?;
```

---

## AST types

These types are returned by `parse()` and consumed by the generation functions.
They are part of the public API but are primarily intended for tooling that needs
to inspect the parsed module.

### `Module`

```rust
pub struct Module {
    pub name: String,
    pub tagging: TaggingMode,
    pub imports: Vec<Import>,
    pub exports: Vec<String>,
    pub definitions: Vec<Definition>,
}
```

### `Definition`

```rust
pub struct Definition {
    pub name: String,
    pub ty: Type,
}
```

### `ParseError`

```rust
pub struct ParseError {
    pub message: String,
    pub line: usize,
    pub column: usize,
}
```

`ParseError` implements `std::fmt::Display` and `std::error::Error`.

---

## See Also

- [rust-generation.md]rust-generation.md -- Rust code generation details, build.rs integration, multi-module projects
- [c-generation.md]c-generation.md -- C code generation details, libcsynta API, multi-module projects
- [asn1-support.md]asn1-support.md -- supported ASN.1 syntax reference