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];
}