# 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);
}
```