export type {{value_type_name}} = (
    {%- for union_type_idx, union_typedef in enumerate(union_typedefs) %}
    | {
        type: {{union_type_idx}};
        value: {{union_typedef.value_type_name}};
    }
    {%- endfor %}
);

export type {{data_type_name}} = (
    {%- for union_typedef in union_typedefs %}
    | {{union_typedef.data_type_name}}
    {%- endfor %}
);

export function {{to_data_name}}(value: {{value_type_name}}): {{data_type_name}} {
    switch (value.type) {
        {%- for union_type_idx, union_typedef in enumerate(union_typedefs) %}
        case {{union_type_idx}}:
            return {{union_typedef.to_data_name}}(value.value);
        {%- endfor %}
        default:
            const _: never = value;
            throw Error();
    }
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function {{from_data_name}}(data: any): {{value_type_name}} {
    const results: {{value_type_name}}[] = [];

    {%- for union_type_idx, union_typedef in enumerate(union_typedefs) %}
    try {
        results.push({
            type: {{union_type_idx}},
            value: {{union_typedef.from_data_name}}(data),
        });
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } catch (rawExc: any) {
        const exc = rawExc as unknown as Error;
        if (exc.name !== "{{DESERIALIZATION_ERROR_NAME}}") {
            throw exc;
        }
    }
    {%- endfor %}

    if (results.length !== 1) {
        {{RAISE_DESERIALIZATION_ERROR}};
    }

    return results[0];
}