synta-codegen 0.1.4

ASN.1 schema parser and Rust code generator for the synta library
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
# synta-codegen

<!-- 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)*

- [Overview]#overview
  - [Target Languages]#target-languages
- [Features]#features
  - [Language & output targets]#language-output-targets
  - [Type system & constraints]#type-system-constraints
  - [Module system]#module-system
  - [C build integration]#c-build-integration
  - [Implementation quality]#implementation-quality
- [Quick Start]#quick-start
  - [Installation]#installation
  - [Basic Usage]#basic-usage
- [Example]#example
- [Multi-File Projects]#multi-file-projects
- [Documentation]#documentation
  - [ASN.1 Reference]#asn1-reference
  - [Language-Specific Generation]#language-specific-generation
  - [Getting Started]#getting-started
  - [Reference]#reference
- [Supported ASN.1 Constructs]#supported-asn1-constructs
  - [Type Definitions]#type-definitions
  - [X.680 Constraints]#x680-constraints
  - [Field Modifiers]#field-modifiers
  - [Module Features]#module-features
- [synta-codegen vs. Manual Implementation]#synta-codegen-vs-manual-implementation
- [Real-World Support]#real-world-support
  - [IMPLICIT-tagged CHOICE variants]#implicit-tagged-choice-variants
- [Development]#development
- [Contributing]#contributing
- [Current Limitations]#current-limitations
- [Optional Features]#optional-features
  - [Regex Validation for PATTERN Constraints]#regex-validation-for-pattern-constraints
  - [Runtime Validation for CONTAINING Constraints]#runtime-validation-for-containing-constraints
- [See Also]#see-also
- [License]#license

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

ASN.1 schema parser and Rust/C code generator for the `synta` library with full X.680 constraint support.

## Overview

`synta-codegen` parses ASN.1 module definitions (.asn1 files) and generates type-safe, validated Rust code or C code using the `synta` library. It supports ITU-T X.680 constraints and generates validated newtypes with runtime checks, eliminating the need to manually write encoding/decoding implementations.

### Target Languages

- **Rust** (default): Generates type-safe Rust code with derive macros and validation
- **C**: Generates C header files with struct definitions and encoder/decoder functions using the libcsynta C API

## Features

### Language & output targets

- **Multi-Language Support** - Generate Rust or C code from the same ASN.1 schema
- **Owned or Zero-Copy String Types** - `StringTypeMode::Borrowed` emits `OctetStringRef<'a>`, `BitStringRef<'a>`, `Utf8StringRef<'a>`, etc. for zero-allocation parse-only workloads (Rust)
- **Idiomatic Code** - PascalCase types, snake_case fields, proper conventions

### Type system & constraints

- **X.680 Constraint Support** - Full support for value ranges, size constraints, permitted alphabet, and more
- **ANY Type Support** - Support for legacy ANY and ANY DEFINED BY types
- **Validated Newtypes** - Generates type-safe wrappers with runtime validation (Rust)
- **DEFAULT Values** - Automatic Default trait implementation (Rust)
- **Named Value Constants** - Generate constants for INTEGER named values
- **Subtype Definitions** - Support for type references with additional constraints
- **PATTERN Regex Validation** - Optional regex validation with `regex` feature flag (Rust only)
- **CONTAINING Validation** - Optional runtime validation of encoded types with `validate_containing` feature (Rust only)

### Module system

- **IMPORTS/EXPORTS** - Full module dependency support with topological ordering
- **Multi-File Projects** - Automatic cross-module use statement generation (Rust) and multi-file output via `--output-dir`
- **Circular Import Detection** - Detects and reports import cycles before code generation (`--check-imports`)

### C build integration

- **Build System Integration** - Generate `CMakeLists.txt` (`--cmake`) or `meson.build` (`--meson`) for C projects
- **C Helper Functions** - `_init`, `_validate`, and `_print` helpers for every C type (`--with-helpers`)

### Implementation quality

- **Zero Dependencies** - No external crates required for code generation

See [../docs/asn1-support.md](../docs/asn1-support.md) for the complete ASN.1 support matrix.

## Quick Start

### Installation

```bash
cargo install synta-codegen
```

Or add to your `Cargo.toml`:

```toml
[build-dependencies]
synta-codegen = "0.1"
```

### Basic Usage

**Command Line (Rust):**
```bash
synta-codegen schema.asn1 -o generated.rs
```

**Command Line (C):**
```bash
# Single-file: generate header, then implementation
synta-codegen schema.asn1 --c -o generated.h
synta-codegen schema.asn1 --impl generated.h -o generated.c

# With helper functions (_init, _validate, _print)
synta-codegen schema.asn1 --c --with-helpers -o generated.h

# Multi-file: headers and implementations together
synta-codegen a.asn1 b.asn1 --c --emit both --output-dir ./generated/

# Generate CMake or Meson build files (single-file)
synta-codegen schema.asn1 --cmake -o CMakeLists.txt
synta-codegen schema.asn1 --meson -o meson.build
```

**Library (owned types, default):**
```rust
use synta_codegen::{parse, generate};

let schema = r#"
    MyModule DEFINITIONS ::= BEGIN
        Person ::= SEQUENCE {
            name UTF8String,
            age INTEGER (0..150)
        }
    END
"#;

let module = parse(schema)?;
let code = generate(&module)?;
```

**Library (zero-copy borrowed types, parse-only workloads):**
```rust
use synta_codegen::{parse, generate_with_config, CodeGenConfig, StringTypeMode};

let module = parse(schema)?;
let config = CodeGenConfig {
    string_type_mode: StringTypeMode::Borrowed,
    ..Default::default()
};
// Emits Utf8StringRef<'a> instead of Utf8String, struct gains <'a> lifetime
let code = generate_with_config(&module, config)?;
```

**C Code Generation:**
```rust
use synta_codegen::{parse, generate_c};

let schema = "...";
let module = parse(schema)?;
let c_code = generate_c(&module)?;
```

See [../docs/api-reference.md](../docs/api-reference.md) for the complete CLI and library API reference,
[../docs/rust-generation.md](../docs/rust-generation.md) for Rust code generation details, and
[../docs/c-generation.md](../docs/c-generation.md) for C code generation and the libcsynta API.

## Example

**Input ASN.1:**
```asn1
Types DEFINITIONS ::= BEGIN

Percentage ::= INTEGER (0..100)

Protocol ::= INTEGER {tcp(6), udp(17), sctp(132)}

User ::= SEQUENCE {
    name IA5String (SIZE (1..64)),
    age Percentage,
    email IA5String OPTIONAL
}

END
```

**Generated Rust:**
```rust
/// INTEGER (0..100)
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Percentage(u8);

impl Percentage {
    pub fn new(value: u8) -> Result<Self, &'static str> {
        let val: i64 = value as i64;
        if (0..=100).contains(&val) {
            Ok(Percentage(value))
        } else {
            Err("must be in range 0..100")
        }
    }
    pub const fn new_unchecked(value: u8) -> Self { Percentage(value) }
    pub const fn get(&self) -> u8 { self.0 }
    pub fn into_inner(self) -> u8 { self.0 }
}

pub type Protocol = Integer;

impl Protocol {
    pub const TCP: i64 = 6;
    pub const UDP: i64 = 17;
    pub const SCTP: i64 = 132;
}

#[derive(Debug, Clone, PartialEq)]
pub struct User {
    pub name: Name,
    pub age: Percentage,
    pub email: Option<IA5String>,
}
```

**Usage:**
```rust
let user = User {
    name: Name::new(IA5String::from("Alice"))?,
    age: Percentage::new(25)?,
    email: None,
};

// Validation at compile time and runtime
let invalid = Percentage::new(150); // Err("must be in range 0..100")
```

## Multi-File Projects

synta-codegen supports automatic cross-module use statement generation and multi-file output:

```bash
# Rust: generate with crate-relative imports
synta-codegen base_types.asn1 --crate-imports -o src/base_types.rs
synta-codegen user_module.asn1 --crate-imports -o src/user_module.rs

# C: generate headers only into a directory (default)
synta-codegen a.asn1 b.asn1 c.asn1 --c --output-dir ./generated

# C: generate both headers and implementations
synta-codegen a.asn1 b.asn1 c.asn1 --c --emit both --output-dir ./generated

# C: generate build file + all C sources in one invocation
synta-codegen a.asn1 b.asn1 c.asn1 --cmake --output-dir ./generated
synta-codegen a.asn1 b.asn1 c.asn1 --meson --output-dir ./generated

# Validate imports without generating code
synta-codegen a.asn1 b.asn1 c.asn1 --check-imports
```

**Generated Rust use statements:**
```rust
use crate::base_types::{Percentage, ShortString};
```

See [../docs/rust-generation.md](../docs/rust-generation.md#9-buildrs-integration) for the complete multi-module build.rs guide.

## Documentation

### ASN.1 Reference
- **[ASN.1 Support]../docs/asn1-support.md** - What ASN.1 syntax is supported and what is not; complete support matrix

### Language-Specific Generation
- **[Rust Generation]../docs/rust-generation.md** - Type mappings, naming, constraint validation, build.rs integration
- **[C Generation]../docs/c-generation.md** - Type mappings, libcsynta API reference, memory contract, arena mode

### Getting Started
- **[Tutorial]../docs/tutorial.md** - Step-by-step guide from basics to real-world examples
- **[API Reference]../docs/api-reference.md** - Complete CLI options, examples, and library API

### Reference
- **[Limitations]../docs/limitations.md** - Unsupported constructs and workarounds
- **[Troubleshooting]../docs/troubleshooting.md** - Common issues and solutions

## Supported ASN.1 Constructs

### Type Definitions
- SEQUENCE, SET, CHOICE
- SEQUENCE OF, SET OF
- All primitive types (INTEGER, BOOLEAN, OCTET STRING, etc.)

### X.680 Constraints
- Value ranges: `INTEGER (0..100)`
- Size constraints: `IA5String (SIZE (1..64))`
- Permitted alphabet: `IA5String (FROM ("0".."9"))`
- PATTERN constraints: `IA5String (PATTERN "[0-9]+")` (with optional `regex` feature)
- CONTAINING constraints: `OCTET STRING (CONTAINING Certificate)` (with optional `validate_containing` feature)
- Combined constraints: `IA5String (SIZE (4..6) FROM ("0".."9"))`
- Union, intersection, complement
- Inner type constraints

### Field Modifiers
- OPTIONAL fields
- DEFAULT values
- Tagged fields ([0] EXPLICIT, [1] IMPLICIT)

### Module Features
- IMPORTS and EXPORTS
- Type references
- Nested definitions

See [../docs/asn1-support.md](../docs/asn1-support.md) for the complete support matrix.

## synta-codegen vs. Manual Implementation

| Aspect | Manual | synta-codegen |
|--------|--------|---------------|
| Type definitions | Manual struct definitions | Auto-generated |
| Constraint validation | Manual checks in constructors | Auto-generated from schema |
| OPTIONAL fields | Manual Option handling | Auto-generated |
| DEFAULT values | Manual Default impl | Auto-generated |
| Type references | Manual imports | Auto-generated use statements |
| Maintenance | Update code when schema changes | Regenerate |

## Real-World Support

synta-codegen can parse and generate code for:
-  X.509 certificates (PKIX schemas), including SET OF RDN fields with correct 0x31 tag
-  X.509 Certificate Revocation Lists (CRL, RFC 5280)
-  PKCS#10 Certificate Signing Requests (CSR, RFC 2986)
-  OCSP request/response (RFC 6960)
-  RFC 3279 algorithm parameter types (DSA/DH domain params, ECDSA signature values, EC domain params)
-  RFC 5755 Attribute Certificates (AC v2: `AttributeCertificate`, `Holder`, `AttCertIssuer`, etc.)
-  RFC 4211 Certificate Request Message Format (CRMF: `CertTemplate`, `ProofOfPossession`, `PKIArchiveOptions`, etc.)
-  RFC 9810 Certificate Management Protocol v3 (CMP: `PKIMessage`, `PKIHeader`, `PKIBody`, etc.)
-  PKCS#7 / CMS (RFC 5652), PKCS#8 (RFC 5958), PKCS#9 (RFC 2985), PKCS#12 (RFC 7292)
-  Kerberos V5 (RFC 4120), SPNEGO (RFC 4178), FAST (RFC 6113)
-  Merkle Tree Certificates (draft-ietf-tls-merkle-tree-certs)
-  LDAP directory schemas
-  SNMP management information bases
-  5G/LTE protocol specifications
-  Custom ASN.1 schemas

### IMPLICIT-tagged CHOICE variants

When a CHOICE variant is annotated with `#[asn1(tag(N, implicit))]`, the codegen
selects the correct decode path based on whether the inner type has a lifetime
parameter:

- **Owned types** (no lifetime): uses `ImplicitTag<T>` as before
- **Borrowed types** (lifetime `'a`): reads the context tag + length and calls
  `<T as DecodeImplicit>::decode_implicit(content_bytes, encoding)` directly,
  avoiding the `for<'b> Decode<'b>` HRTB that borrowed types cannot satisfy

This is transparent to schema authors: write `[N] IMPLICIT SomeType` in the schema
and the codegen picks the right path automatically.

Note: IMPLICIT tagging of a CHOICE inner type is prohibited by ASN.1 (CHOICE has
no single tag to replace).  If the inner type of a variant is itself a CHOICE, use
EXPLICIT tagging: `[N] EXPLICIT ChoiceType`.  The codegen emits EXPLICIT when the
inner type is a CHOICE or a type alias for one.

## Development

Run tests:
```bash
cargo test -p synta-codegen
```

Build the CLI:
```bash
cargo build --release -p synta-codegen
```

## Contributing

Contributions are welcome! Please see the main [synta repository](https://codeberg.org/abbra/synta) for contribution guidelines.

## Current Limitations

- Table constraints and information objects not yet implemented
- Some X.680 advanced features not yet supported

See [../docs/limitations.md](../docs/limitations.md) for details and workarounds.

## Optional Features

### Regex Validation for PATTERN Constraints

To enable runtime regex validation for PATTERN constraints, add the `regex` feature when using the generated code:

```toml
[dependencies]
synta = { version = "0.1", features = ["regex"] }
regex = "1.10"
once_cell = "1.19"
```

**Example:**
```asn1
Email ::= IA5String (PATTERN "[a-z]+@[a-z]+\\.com")
```

**Generated code (with `regex` feature):**
```rust
// Static regex pattern compiled once
static PATTERN_0: Lazy<Regex> = Lazy::new(|| Regex::new(r"[a-z]+@[a-z]+\.com").unwrap());

pub fn new(value: IA5String) -> Result<Self, String> {
    if !PATTERN_0.is_match(value.as_ref()) {
        return Err(format!("value does not match pattern: [a-z]+@[a-z]+\\.com"));
    }
    Ok(Email(value))
}
```

**Without the `regex` feature**, the generated code includes a comment noting that pattern validation is disabled.

### Runtime Validation for CONTAINING Constraints

To enable runtime validation for CONTAINING constraints, add the `validate_containing` feature when using the generated code:

```toml
[dependencies]
synta = { version = "0.1", features = ["validate_containing"] }
```

**Example:**
```asn1
EncodedCertificate ::= OCTET STRING (CONTAINING Certificate)
```

**Generated code (with `validate_containing` feature):**
```rust,ignore
pub fn new(value: OctetString) -> Result<Self, String> {
    // Validate that value contains a valid DER-encoded Certificate
    use synta::der::Decoder;
    let bytes = value.as_ref();
    let mut decoder = Decoder::new(bytes, synta::Encoding::Der)?;
    let _decoded: Certificate = decoder.decode().map_err(|e| {
        format!("invalid Certificate in CONTAINING constraint: {}", e)
    })?;
    // Verify complete consumption
    if !decoder.is_empty() {
        return Err("trailing bytes after Certificate in CONTAINING constraint".into());
    }
    Ok(EncodedCertificate(value))
}
```

**Without the `validate_containing` feature**, the generated code includes a comment noting that CONTAINING validation is disabled. This allows for zero-overhead when validation is not needed.

## See Also

- [synta]../README.md - The main ASN.1 encoding/decoding library
- [synta-derive]../synta-derive/README.md - Derive macros for ASN.1 types
- [ITU-T X.680]https://www.itu.int/rec/T-REC-X.680 - ASN.1 specification
- [ITU-T X.690]https://www.itu.int/rec/T-REC-X.690 - BER/DER/CER encoding rules

## License

Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE]../LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT]../LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.