# Encoding
This walkthrough covers encoding ASN.1 structures to DER with the `synta` library.
## Creating an encoder
```rust
use synta::{Encoder, Encoding};
// DER encoding (default for cryptographic data)
let mut encoder = Encoder::new(Encoding::Der);
```
## Quick encode with `ToDer`
For the common case of encoding a single value, `ToDer` removes the need to
construct an `Encoder` manually. Import the trait and call `to_der()` or
`to_ber()` directly on any value that implements `Encode`:
```rust,ignore
use synta::{Integer, ToDer};
let n = Integer::from(42i32);
// Encode to DER
let der_bytes: Vec<u8> = n.to_der()?;
// der_bytes == [0x02, 0x01, 0x2A]
// Encode to BER (same bytes for simple types; useful for constructed types
// that may use indefinite-length encoding)
let ber_bytes: Vec<u8> = n.to_ber()?;
```
`ToDer` is a blanket impl — it is automatically available on every type that
implements `Encode`, including structs generated by `synta-codegen`.
When you need to write multiple values into a shared buffer, or want fine-grained
control over the encoding, use the `Encoder` API directly (see
[Creating an encoder](#creating-an-encoder) above).
## Encoding primitive types
### Integer
```rust
use synta::{Encoder, Encoding, Integer};
let value = Integer::from(42i32);
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&value)?;
let encoded = encoder.finish()?;
// encoded = [0x02, 0x01, 0x2A]
```
Create from different numeric types:
```rust
use synta::Integer;
let i1 = Integer::from(42i32);
let i2 = Integer::from(12345i64);
let i3 = Integer::from(i128::MAX);
```
### Boolean
```rust
use synta::types::primitive::Boolean;
let b = Boolean::new(true);
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&b)?;
```
### OctetString
```rust
use synta::types::string::OctetString;
let data = vec![0xDE, 0xAD, 0xBE, 0xEF];
let octets = OctetString::new(data);
encoder.encode(&octets)?;
```
### ObjectIdentifier
```rust
use synta::types::oid::ObjectIdentifier;
let components = &[1, 2, 840, 113549, 1, 1, 1]; // RSA Encryption
let oid = ObjectIdentifier::new(components)?;
encoder.encode(&oid)?;
```
## Encoding string types
```rust
use synta::types::string::{Utf8String, PrintableString, IA5String};
let utf8 = Utf8String::new("Hello, World!".to_string());
encoder.encode(&utf8)?;
let printable = PrintableString::new("Hello World".to_string())?;
encoder.encode(&printable)?;
let ia5 = IA5String::new("ASCII only".to_string())?;
encoder.encode(&ia5)?;
```
## Encoding time types
```rust
use synta::types::time::{UtcTime, GeneralizedTime};
let utc = UtcTime::new(2023, 2, 23, 12, 0, 0)?;
encoder.encode(&utc)?;
let gen = GeneralizedTime::new(2023, 2, 23, 12, 0, 0, None)?;
encoder.encode(&gen)?;
```
## Encoding constructed types
### SEQUENCE
```rust
use synta::types::constructed::{Element, Sequence};
use synta::types::primitive::{Boolean, Integer};
use synta::{Encoder, Encoding};
let mut seq = Sequence::new();
seq.push(Element::Integer(Integer::from(42)));
seq.push(Element::Boolean(Boolean::new(true)));
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&seq)?;
let encoded = encoder.finish()?;
```
### SET
```rust
use synta::types::constructed::{Element, Set};
let mut set = Set::new();
set.push(Element::Integer(Integer::from(10)));
set.push(Element::Integer(Integer::from(5)));
// In DER, elements are sorted lexicographically on encode
```
### SequenceOf
```rust
use synta::types::constructed::SequenceOf;
use synta::types::primitive::Integer;
let mut seq_of = SequenceOf::<Integer>::new();
seq_of.push(Integer::from(1));
seq_of.push(Integer::from(2));
seq_of.push(Integer::from(3));
encoder.encode(&seq_of)?;
```
## Encoding tagged types
### EXPLICIT tag
```rust
use synta::types::tagged::ExplicitTag;
use synta::types::primitive::Integer;
// [0] EXPLICIT Integer
let tagged = ExplicitTag::context_specific(0, Integer::from(42));
encoder.encode(&tagged)?;
```
### IMPLICIT tag
```rust
use synta::types::tagged::ImplicitTag;
use synta::types::primitive::Integer;
// [0] IMPLICIT Integer
let tagged = ImplicitTag::context_specific(0, Integer::from(42));
encoder.encode(&tagged)?;
```
## Building complex structures
```rust
use synta::*;
use synta::types::string::Utf8StringRef;
use synta::types::constructed::Sequence;
fn build_info() -> Sequence<'static> {
let mut seq = Sequence::new();
// Version
seq.push(Element::Integer(Integer::from(3)));
// Serial number
seq.push(Element::Integer(Integer::from(123456)));
// Subject (Utf8StringRef borrows from a &'static str literal)
let mut subject = Sequence::new();
subject.push(Element::Utf8String(Utf8StringRef::new("Example")));
seq.push(Element::Sequence(subject));
seq
}
```
## Serde integration
Enable the `serde` feature to add JSON serialization support:
```toml
[dependencies]
synta = { version = "0.1", features = ["serde"] }
serde_json = "1"
```
JSON representations:
| `Boolean` | `true` / `false` |
| `Integer` | lowercase hex string, e.g. `"2a"` |
| `Null` | `null` |
| `Real` | float |
| `OctetString` | lowercase hex string, e.g. `"deadbeef"` |
| `BitString` | `{"bytes":"<hex>","unused_bits":<n>}` |
| Text strings | plain string |
| `ObjectIdentifier` | dotted-decimal, e.g. `"1.2.840.113549"` |
| `UtcTime` | `"YYMMDDHHMMSSZ"` |
| `GeneralizedTime` | `"YYYYMMDDHHMMSSZ"` |
| `SequenceOf<T>` | JSON array |
| `Element` | `{"type":"<Name>","value":<value>}` |
Example — DER to JSON to DER round-trip:
```rust
use synta::{Decoder, Encoder, Encoding, Integer};
let der = vec![0x02, 0x02, 0x30, 0x39]; // INTEGER 12345
let mut decoder = Decoder::new(&der, Encoding::Der);
let value: Integer = decoder.decode().unwrap();
let json = serde_json::to_string(&value).unwrap(); // "\"3039\""
let restored: Integer = serde_json::from_str(&json).unwrap();
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&restored).unwrap();
assert_eq!(encoder.finish().unwrap(), der);
```
Serialize an `Element` tree:
```rust
use synta::{Decoder, Element, Encoding};
let der = [
0x30, 0x09, // SEQUENCE
0x02, 0x01, 0x01, // INTEGER 1
0x01, 0x01, 0xff, // BOOLEAN TRUE
0x05, 0x00, // NULL
];
let mut decoder = Decoder::new(&der, Encoding::Der);
let element: Element = decoder.decode().unwrap();
let json = serde_json::to_string_pretty(&element).unwrap();
```
Note: `Element`, `Sequence`, and `Set` implement `Serialize` only (borrowed
lifetimes prevent `Deserialize`). `SequenceOf<T>`, `SetOf<T>`,
`ExplicitTag<T>`, and `ImplicitTag<T>` implement both.
## Performance tips
**Reuse the decoder buffer** — decode multiple values from the same decoder:
```rust
let mut decoder = Decoder::new(&data, Encoding::Der);
let int1: Integer = decoder.decode()?;
let int2: Integer = decoder.decode()?;
```
**Reuse the encode buffer** — clear and reuse for batches:
```rust
let mut buffer = Vec::with_capacity(1024);
for item in &items {
buffer.clear();
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(item)?;
buffer.extend_from_slice(&encoder.finish()?);
send(&buffer);
}
```
**SmallVec optimization** — integers up to 16 bytes avoid heap allocation:
```rust
// These do not allocate:
let i1 = Integer::from(42i32); // 1–4 bytes inline
let i2 = Integer::from(i64::MAX); // 8 bytes inline
let i3 = Integer::from(i128::MAX);// 16 bytes inline
// This allocates:
let huge = Integer::from_bytes(&[0xFF; 32]); // > 16 bytes
```
## Next steps
- [PKI Workflow](pki-workflow.md) — certificate, CRL, and OCSP end to end
- [ASN.1 Constructed Types](../asn1/constructed.md) — SEQUENCE, SET, CHOICE details
- [Code Generation](../codegen/overview.md) — generate typed structs from ASN.1 schemas