synta 0.2.2

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

## Boolean

```rust
use synta::types::primitive::Boolean;

let b = Boolean::new(true);
let value: bool = b.value();
```

DER encodes `true` as `0xFF` (only `0xFF` is legal for DER; BER accepts any
non-zero byte).

## Integer

```rust
use synta::types::primitive::Integer;

// Create from different types
let i1 = Integer::from(42i32);
let i2 = Integer::from(12345i64);
let i3 = Integer::from(i128::MAX);

// Convert to native types
let val_i32:  i32  = i1.as_i32()?;
let val_i64:  i64  = i1.as_i64()?;
let val_i128: i128 = i3.as_i128()?;

// Access raw big-endian two's complement bytes
let bytes: &[u8] = i1.as_bytes();
```

SmallVec optimization: integers up to 16 bytes are stored inline without heap
allocation.

## Null

```rust
use synta::types::primitive::Null;

// Null has no value; it is just a tag marker
encoder.encode(&Null)?;
```

## Real

```rust
use synta::types::primitive::Real;

let r = Real::from(3.14f64);
encoder.encode(&r)?;
```

## Enumerated

`Enumerated` is a thin newtype over `i64` that encodes with the ASN.1
ENUMERATED tag (`0x0a`).  It is used for typed enum-like fields where the
numeric values are defined by a schema (e.g., OCSP `OCSPResponseStatus`, CRL
reason codes).

```rust
use synta::types::primitive::Enumerated;

// Construct from an integer value
let e = Enumerated::from_i32(0);
let e = Enumerated::from_i64(2i64);

// Read the wrapped value
let v: i64 = e.as_i64().unwrap();

// Decode from DER (tag 0x0a)
use synta::{Decoder, Encoding};
let der: &[u8] = &[0x0a, 0x01, 0x00]; // ENUMERATED 0
let mut dec = Decoder::new(der, Encoding::Der);
let status: Enumerated = dec.decode().unwrap();
assert_eq!(status.as_i64().unwrap(), 0);
```

## ObjectIdentifier

```rust
use synta::types::oid::ObjectIdentifier;
use std::str::FromStr;

// Create from components
let components = &[1, 2, 840, 113549, 1, 1, 1]; // RSA Encryption
let oid = ObjectIdentifier::new(components)?;

// Create from string notation
let oid2 = ObjectIdentifier::from_str("1.2.840.113549.1.1.1")?;

// Access components
let comps: &[u32] = oid.components();

// Format as string
let oid_str = oid.to_string(); // "1.2.840.113549.1.1.1"

// Encode/decode raw DER content bytes (without the 0x06 tag and length)
// Useful for non-DER formats such as CBOR (RFC 9090 tag 111).
let content: Vec<u8> = oid.to_content_bytes();
let oid3 = ObjectIdentifier::from_content_bytes(&content)?;
assert_eq!(oid, oid3);
```

OID components are stored in SmallVec โ€” up to 8 components are inline without
heap allocation.

`to_content_bytes` returns the raw base-128 arc encoding without the `0x06`
tag byte or the DER length field.  It is the symmetric counterpart to
`from_content_bytes` and is used by `synta-cbor` to encode OIDs as RFC 9090
tagged byte strings.

## OctetString

```rust
use synta::types::string::OctetString;

let data = vec![0xDE, 0xAD, 0xBE, 0xEF];
let octets = OctetString::new(data);

let bytes: &[u8] = octets.as_bytes();
let owned: Vec<u8> = octets.into_vec(); // consumes and returns Vec<u8>
```

Zero-copy variant (borrowed from the decoder buffer):

```rust
use synta::types::string::OctetStringRef;

let octets_ref: OctetStringRef = decoder.decode()?;
let bytes: &[u8] = octets_ref.as_bytes();
```

## BitString

```rust
use synta::types::string::BitString;

// Create from bytes + unused bits count
let bs = BitString::new(vec![0b10110000], 4)?; // 4 significant bits
let bytes: &[u8] = bs.as_bytes();
let unused: u8 = bs.unused_bits();
```

Zero-copy variant:

```rust
use synta::types::string::BitStringRef;

let bs_ref: BitStringRef = decoder.decode()?;
```

## Time types

### UTCTime

UTCTime encodes year as two digits (00โ€“99), interpreted per RFC 5280 ยง4.1.2.5
as 1950โ€“2049.

```rust
use synta::types::time::UtcTime;

// (year, month, day, hour, minute, second)
let utc = UtcTime::new(2023, 2, 23, 12, 0, 0)?;
```

### GeneralizedTime

GeneralizedTime encodes the full four-digit year.

```rust
use synta::types::time::GeneralizedTime;

// (year, month, day, hour, minute, second, optional_milliseconds)
let gen = GeneralizedTime::new(2023, 2, 23, 12, 0, 0, None)?;
```

## Serde representations

When the `serde` feature is enabled:

| Type | JSON representation |
|------|---------------------|
| `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>}` |
| `ObjectIdentifier` | dotted-decimal, e.g. `"1.2.840.113549"` |
| `UtcTime` | `"YYMMDDHHMMSSZ"` |
| `GeneralizedTime` | `"YYYYMMDDHHMMSSZ"` or `"YYYYMMDDHHMMSS.mmmZ"` |