# Code Generation Overview
`synta-codegen` transforms ASN.1 module definitions into Rust source code.
It can be used as a command-line tool or as a Rust library in `build.rs`.
```mermaid
flowchart LR
S[("schema.asn1")]
P("parse()")
A["Module AST"]
G("generate_with_config()")
R[("OUT_DIR/<br/>generated_types.rs")]
M("include!()")
L[("src/lib.rs")]
S --> P --> A --> G --> R --> M --> L
C{{"CodeGenConfig<br/>import style · StringTypeMode<br/>DeriveMode"}}
C -.->|shapes output| G
```
## Quick start: CLI
Generate Rust from an ASN.1 schema file:
```sh
synta-codegen --lang rust schema.asn1 -o src/generated.rs
```
`--lang rust` is the default and may be omitted.
Generate into a directory (one file per ASN.1 module):
```sh
synta-codegen schema.asn1 --output-dir src/gen/
```
## Quick start: Library API
```rust
use synta_codegen::{parse, generate, generate_with_config, CodeGenConfig};
let src = std::fs::read_to_string("schema.asn1")?;
let module = parse(&src)?;
// Defaults: std paths, no import prefix, owned string types
let rust_code = generate(&module)?;
// With crate-relative imports
let rust_code = generate_with_config(&module, CodeGenConfig::with_crate_imports())?;
```
## build.rs integration
Add `synta-codegen` as a build dependency:
```toml
[build-dependencies]
synta-codegen = { path = "../synta-codegen" }
```
In `build.rs`:
```rust
use std::path::PathBuf;
use synta_codegen::{parse, generate_with_config, CodeGenConfig};
fn main() {
let schema = std::fs::read_to_string("schema.asn1")
.expect("failed to read schema.asn1");
let module = parse(&schema).expect("failed to parse ASN.1");
let config = CodeGenConfig::with_crate_imports();
let code = generate_with_config(&module, config)
.expect("failed to generate Rust code");
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
std::fs::write(out_dir.join("generated_types.rs"), code)
.expect("failed to write generated_types.rs");
println!("cargo:rerun-if-changed=schema.asn1");
}
```
In `src/lib.rs`:
```rust
include!(concat!(env!("OUT_DIR"), "/generated_types.rs"));
```
## Multi-module build.rs
When schemas import from each other, list them in dependency order:
```rust
use synta_codegen::{parse, generate_with_config, CodeGenConfig};
use std::{fs, path::PathBuf};
fn main() {
let modules = ["base_types", "user_module", "admin_module"];
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
let config = CodeGenConfig::with_crate_imports();
for name in &modules {
let schema = fs::read_to_string(format!("schemas/{name}.asn1"))
.unwrap_or_else(|e| panic!("failed to read {name}.asn1: {e}"));
let module = parse(&schema)
.unwrap_or_else(|e| panic!("failed to parse {name}.asn1: {e}"));
let code = generate_with_config(&module, config.clone())
.unwrap_or_else(|e| panic!("failed to generate {name}: {e}"));
fs::write(out_dir.join(format!("{name}.rs")), code)
.unwrap_or_else(|e| panic!("failed to write {name}.rs: {e}"));
println!("cargo:rerun-if-changed=schemas/{name}.asn1");
}
}
```
In `src/lib.rs`:
```rust
mod base_types { include!(concat!(env!("OUT_DIR"), "/base_types.rs")); }
mod user_module { include!(concat!(env!("OUT_DIR"), "/user_module.rs")); }
mod admin_module { include!(concat!(env!("OUT_DIR"), "/admin_module.rs")); }
pub use base_types::{BaseType1, BaseType2};
pub use user_module::User;
```
## Recommended project layout
```
my-project/
├── Cargo.toml
├── build.rs
├── schemas/
│ ├── base_types.asn1
│ ├── user_module.asn1
│ └── admin_module.asn1
└── src/
├── lib.rs (contains the include! macros above)
└── manual.rs (hand-written code that uses the generated types)
```
## What is NOT generated
The following are parsed and understood by synta-codegen but produce no Rust
output:
- Table constraints and information object class instances/object sets.
CLASS definitions emit a documentation comment but no DER-encodable type.
- Serde derive attributes (available as a separate synta-derive feature).
- Trait implementations beyond `Debug`, `Clone`, and `PartialEq`.
- Explicit encode/decode methods (handled by the synta derive macros at
compile time).
- User-defined constraint validation hooks.
## Next steps
- [Type Mappings](type-mappings.md) — ASN.1 to Rust type table
- [Naming](naming.md) — identifier conversion rules
- [OPTIONAL and DEFAULT](optional-default.md) — optional field handling
- [Tagged Fields](tagged-fields.md) — IMPLICIT and EXPLICIT tags
- [Imports](imports.md) — IMPORTS and module references
- [Owned vs Borrowed](owned-vs-borrowed.md) — StringTypeMode and lifetimes
- [Constraints](constraints.md) — value/size/alphabet constraint validation
- [no_std](no-std.md) — no_std and alloc support