synta 0.1.8

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# Owned vs Borrowed Types

Several ASN.1 string and binary types have two Rust representations in synta:

| ASN.1 type | Owned form | Zero-copy form |
|---|---|---|
| `OCTET STRING` | `OctetString` | `OctetStringRef<'a>` |
| `BIT STRING` | `BitString` | `BitStringRef<'a>` |
| `UTF8String` | `Utf8String` | `Utf8StringRef<'a>` |
| `PrintableString` | `PrintableString` | `PrintableStringRef<'a>` |
| `IA5String` | `IA5String` | `IA5StringRef<'a>` |

`CodeGenConfig::string_type_mode` selects which form synta-codegen emits.

## Default: owned types

`StringTypeMode::Owned` (the default) emits the owned forms.  Owned types
heap-allocate their contents on decode and have no lifetime parameter.  This is
the most convenient choice when you need to construct structs programmatically
(e.g., in tests or message builders).

```asn1
Msg ::= SEQUENCE {
    label UTF8String,
    data  OCTET STRING
}
```

Generated Rust (default):

```rust
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "derive", derive(Asn1Sequence))]
pub struct Msg {
    pub label: Utf8String,
    pub data: OctetString,
}
```

## Borrowed mode: zero-copy Ref types

`StringTypeMode::Borrowed` emits the `Ref` forms that borrow directly from the
decoder's input buffer.  No heap allocation occurs for the string content at
decode time.  This is optimal for parse-only workloads such as X.509 certificate
inspection, where structs are decoded, inspected, and discarded — never
constructed from scratch.

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

let config = CodeGenConfig {
    string_type_mode: StringTypeMode::Borrowed,
    ..Default::default()
};
let code = generate_with_config(&module, config)?;
```

Generated Rust (borrowed mode):

```rust
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "derive", derive(Asn1Sequence))]
pub struct Msg<'a> {
    pub label: Utf8StringRef<'a>,
    pub data: OctetStringRef<'a>,
}
```

## Which types are affected

Only the five types listed in the table above are affected.  Other string types
— `TeletexString`, `UniversalString`, `BmpString`, `GeneralString`,
`NumericString`, `VisibleString` — have no `Ref` variant in synta and are always
emitted as owned types regardless of the mode.

Type aliases inherit the mode:

```asn1
MyLabel ::= UTF8String
```

Borrowed mode emits:

```rust
pub type MyLabel<'a> = Utf8StringRef<'a>;
```

## Lifetime propagation

When a struct contains a field of a borrowed type (directly or transitively),
synta-codegen adds a `'a` lifetime parameter to that struct.  Structs that only
contain owned types or unaffected types receive no lifetime parameter.

```asn1
Inner ::= SEQUENCE { name UTF8String }
Outer ::= SEQUENCE { inner Inner, count INTEGER }
```

Borrowed mode:

```rust
pub struct Inner<'a> { pub name: Utf8StringRef<'a> }
pub struct Outer<'a> { pub inner: Inner<'a>, pub count: Integer }
```

`Outer` gains `<'a>` because it contains `Inner<'a>`.

## Named bit strings are always owned

A `BIT STRING` with named bits (a named-bit list) is always emitted as an owned
`BitString` regardless of mode, because it is decoded into a concrete bit-field
type and the bit constants are expressed as plain `u32` offsets into it.

```asn1
KeyUsage ::= BIT STRING {
    digitalSignature (0),
    keyEncipherment  (2)
} (SIZE (32..MAX))
```

Generated Rust (both modes):

```rust
pub struct KeyUsage(pub synta::BitString); // always owned

impl KeyUsage {
    pub const DIGITAL_SIGNATURE: u32 = 0;
    pub const KEY_ENCIPHERMENT: u32 = 2;
}
```

## Choosing a mode

| Scenario | Recommended mode |
|----------|-----------------|
| Parse-only / inspection workload | `Borrowed` — zero allocation for string content |
| Building or mutating structs | `Owned` — no lifetime parameter to manage |
| Mixed (parse + build) | `Owned` (simpler) or split into separate types |