# 6. `serde_usage.rs` — Serde serialization of ASN.1 types
[← Example index](index.md) · [serde_usage.rs on Codeberg](https://codeberg.org/abbra/synta/src/branch/main/examples/serde_usage.rs)
Use the optional `serde` feature to convert synta's ASN.1 types (Integer,
OctetString, OID, Sequence, …) to and from JSON. Documents the JSON
representation of each primitive type. Requires `--features serde`.
## Source
```rust,ignore
//! Example: Serde serialization and deserialization of ASN.1 types
//!
//! This example shows how to use the optional `serde` feature to convert
//! synta's ASN.1 types to and from JSON (or any other serde-supported format).
//!
//! Key formats used for each type:
//!
//! | `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 string, e.g. `"1.2.840.113549"` |
//! | `UtcTime` | `"YYMMDDHHMMSSZ"` |
//! | `GeneralizedTime` | `"YYYYMMDDHHMMSSZ"` or `"YYYYMMDDHHMMSS.mmmZ"` |
//! | `SequenceOf<T>` | JSON array |
//! | `Element` | `{"type":"<Name>","value":<value>}` |
//! | `ExplicitTag<T>` | `{"tag":{...},"value":<value>}` |
//!
//! Run with:
//! cargo run --example serde_usage --features serde
#[cfg(feature = "serde")]
fn main() {
// All the types we need are re-exported directly from the crate root.
use synta::{
Boolean, Decoder, Element, Encoder, Encoding, ExplicitTag, GeneralizedTime, Integer, Null,
ObjectIdentifier, OctetString, Real, SequenceOf, UtcTime, Utf8String,
};
println!("=== Serde Integration Example ===\n");
// -------------------------------------------------------------------------
// 1. Serialize individual ASN.1 types to JSON
// -------------------------------------------------------------------------
println!("1. Primitive types → JSON\n");
let b = Boolean::new(true);
println!(
" Boolean(true) → {}",
serde_json::to_string(&b).unwrap()
);
let i = Integer::from_i64(255);
println!(
" Integer(255) → {}",
serde_json::to_string(&i).unwrap()
);
let n = Null;
println!(
" Null → {}",
serde_json::to_string(&n).unwrap()
);
let r = Real::new(2.5);
println!(
" Real(3.14) → {}",
serde_json::to_string(&r).unwrap()
);
let os = OctetString::new(vec![0xCA, 0xFE, 0xBA, 0xBE]);
println!(
" OctetString → {}",
serde_json::to_string(&os).unwrap()
);
let s = Utf8String::new("hello, ASN.1".to_string());
println!(
" Utf8String → {}",
serde_json::to_string(&s).unwrap()
);
let oid = ObjectIdentifier::new(&[1, 2, 840, 113549, 1, 1, 11]).unwrap(); // sha256WithRSAEncryption
println!(
" ObjectIdentifier → {}",
serde_json::to_string(&oid).unwrap()
);
let t = UtcTime::new(2024, 6, 15, 12, 0, 0).unwrap();
println!(
" UtcTime → {}",
serde_json::to_string(&t).unwrap()
);
let gt = GeneralizedTime::new(2024, 6, 15, 12, 0, 0, Some(500)).unwrap();
println!(
" GeneralizedTime → {}",
serde_json::to_string(>).unwrap()
);
// -------------------------------------------------------------------------
// 2. Deserialize JSON back into ASN.1 types
// -------------------------------------------------------------------------
println!("\n2. JSON → ASN.1 types (deserialization)\n");
let i2: Integer = serde_json::from_str("\"ff\"").unwrap();
println!(" \"ff\" → Integer: {}", i2.as_i64().unwrap());
let oid2: ObjectIdentifier = serde_json::from_str("\"2.5.4.3\"").unwrap(); // commonName
println!(" \"2.5.4.3\" → OID: {:?}", oid2.components());
let t2: UtcTime = serde_json::from_str("\"240101000000Z\"").unwrap();
println!(
" \"240101000000Z\" → UtcTime: year={}, month={}, day={}",
t2.year, t2.month, t2.day
);
let os2: OctetString = serde_json::from_str("\"cafebabe\"").unwrap();
println!(
" \"cafebabe\" → OctetString: {} bytes",
os2.as_bytes().len()
);
// -------------------------------------------------------------------------
// 3. Round-trip: DER → synta types → JSON → synta types → DER
// -------------------------------------------------------------------------
println!("\n3. DER → JSON → DER round-trip\n");
// Start with DER-encoded INTEGER 12345
let der_bytes = vec![0x02, 0x02, 0x30, 0x39];
let mut decoder = Decoder::new(&der_bytes, Encoding::Der);
let decoded_int: Integer = decoder.decode().unwrap();
// Serialize to JSON
let json = serde_json::to_string(&decoded_int).unwrap();
println!(" DER {:02X?} → JSON {}", der_bytes, json);
// Deserialize from JSON
let restored: Integer = serde_json::from_str(&json).unwrap();
// Re-encode to DER
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&restored).unwrap();
let re_encoded = encoder.finish().unwrap();
println!(
" JSON {} → DER {:02X?} (matches: {})",
json,
re_encoded,
re_encoded == der_bytes
);
// -------------------------------------------------------------------------
// 4. SequenceOf serializes as a JSON array
// -------------------------------------------------------------------------
println!("\n4. SequenceOf<Integer> → JSON array\n");
let mut seq: SequenceOf<Integer> = SequenceOf::new();
seq.push(Integer::from_i64(1));
seq.push(Integer::from_i64(2));
seq.push(Integer::from_i64(3));
let json = serde_json::to_string(&seq).unwrap();
println!(" SequenceOf([1,2,3]) → {}", json);
let seq2: SequenceOf<Integer> = serde_json::from_str(&json).unwrap();
println!(
" Deserialized length: {} (matches: {})",
seq2.len(),
seq2.len() == 3
);
// -------------------------------------------------------------------------
// 5. ExplicitTag carries its outer tag into JSON
// -------------------------------------------------------------------------
println!("\n5. ExplicitTag → JSON\n");
let tagged = ExplicitTag::context_specific(0, Integer::from_i64(42));
let json = serde_json::to_string(&tagged).unwrap();
println!(" [0] EXPLICIT INTEGER 42 → {}", json);
let tagged2: ExplicitTag<Integer> = serde_json::from_str(&json).unwrap();
println!(
" Deserialized: tag_number={}, value={}",
tagged2.tag().number(),
tagged2.inner().as_i64().unwrap()
);
// -------------------------------------------------------------------------
// 6. Element enum — serialize a parsed ASN.1 tree as JSON
// -------------------------------------------------------------------------
println!("\n6. ASN.1 Element tree → JSON\n");
// Parse a small DER-encoded SEQUENCE containing an OID and an INTEGER:
// SEQUENCE {
// OID 1.2.840.113549
// INTEGER 1
// }
// SEQUENCE { OID 1.2.840.113549, INTEGER 1 }
// OID = 06 06 2A 86 48 86 F7 0D (8 bytes)
// INT = 02 01 01 (3 bytes)
// Content total = 11 = 0x0B
let der = [
0x30, 0x0B, // SEQUENCE, 11 bytes of content
0x06, 0x06, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, // OID 1.2.840.113549
0x02, 0x01, 0x01, // INTEGER 1
];
let mut decoder = Decoder::new(&der, Encoding::Der);
let element: Element = decoder.decode().unwrap();
let json = serde_json::to_string_pretty(&element).unwrap();
println!(" Parsed element as JSON:\n{}", json);
}
#[cfg(not(feature = "serde"))]
fn main() {
println!("This example requires the 'serde' feature.");
println!("Run with: cargo run --example serde_usage --features serde");
}
```