synta 0.1.6

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


This page documents how synta-codegen generates C code for ASN.1 CHOICE types.

## Struct Layout

A CHOICE type generates a tagged union: an enum for the active variant plus a
union of all variant types:

```c
typedef enum {
    TypeName_TAG_Variant1,
    TypeName_TAG_Variant2,
    /* ... */
} TypeNameTag;

typedef struct {
    TypeNameTag tag;
    union {
        Variant1Type variant1;
        Variant2Type variant2;
        /* ... */
    } value;
} TypeName;
```

## Decode Pattern

The generated decode function calls `synta_decoder_peek_tag()` on the decoder
(without entering any container) and dispatches to the variant's decode
function based on the tag class and number:

```c,ignore
SyntaTag peeked;
err = synta_decoder_peek_tag(decoder, &peeked);
if (err != SyntaErrorCode_Success) return err;

if (peeked.class_ == SyntaTagClass_Universal && peeked.number == 16) {
    out->tag = TypeName_TAG_Variant1;
    return Variant1Type_decode(decoder, &out->value.variant1);
} else if (peeked.class_ == SyntaTagClass_Universal && peeked.number == 2) {
    out->tag = TypeName_TAG_Variant2;
    return Variant2Type_decode(decoder, &out->value.variant2);
}
return SyntaErrorCode_InvalidTag;
```

## Encode Pattern

The generated encode function switches on `value->tag`:

```c,ignore
switch (value->tag) {
case TypeName_TAG_Variant1:
    return Variant1Type_encode(encoder, &value->value.variant1);
case TypeName_TAG_Variant2:
    return Variant2Type_encode(encoder, &value->value.variant2);
default:
    return SyntaErrorCode_InvalidTag;
}
```

## Free Pattern

The generated free function also switches on `tag` to call the correct
variant's cleanup:

```c
void TypeName_free(TypeName *value) {
    if (value == NULL) return;
    switch (value->tag) {
    case TypeName_TAG_Variant1:
        Variant1Type_free(&value->value.variant1);
        break;
    case TypeName_TAG_Variant2:
        Variant2Type_free(&value->value.variant2);
        break;
    default:
        break;
    }
}
```

## Example

```asn1
AttributeValue ::= CHOICE {
    utf8String    UTF8String,
    printable     PrintableString,
    ia5String     IA5String
}
```

Generated types:

```c
typedef enum {
    AttributeValue_TAG_utf8String,
    AttributeValue_TAG_printable,
    AttributeValue_TAG_ia5String,
} AttributeValueTag;

typedef struct {
    AttributeValueTag tag;
    union {
        SyntaOctetString *utf8String;
        SyntaOctetString *printable;
        SyntaOctetString *ia5String;
    } value;
} AttributeValue;
```

Usage:

```c,ignore
AttributeValue av = {0};
SyntaErrorCode err = AttributeValue_decode(decoder, &av);
if (err == SyntaErrorCode_Success) {
    switch (av.tag) {
    case AttributeValue_TAG_utf8String:
        /* use av.value.utf8String */
        break;
    case AttributeValue_TAG_printable:
        /* use av.value.printable */
        break;
    default:
        break;
    }
    AttributeValue_free(&av);
}
```