export type {{ident}} =
{%- let type_variant = ident.clone() %}
{%- for variant in variants -%}
{%- match variant -%}
{%- when EnumVariantDeclaration::Unit with { ident, value } %}
| { tag: '{{ident}}' }
{%- when EnumVariantDeclaration::Unnamed with { ident, types } %}
{%- if types.len() == 1 %}
| { tag: '{{ident}}'; value: {{ variant.first_type().ts_type() }} }
{%- else %}
| { tag: '{{ident}}'; value: {{type_variant}}_{{ident}} }
{%- endif -%}
{%- when EnumVariantDeclaration::Named with { ident, types } %}
| { tag: '{{ident}}'; value: {{type_variant}}_{{ident}} }
{%- endmatch -%}
{% endfor -%}
;
{%- for variant in variants -%}
{%- match variant -%}
{%- when EnumVariantDeclaration::Unnamed with { ident, types } -%}
{%- if types.len() > 1 %}
export interface {{type_variant}}_{{ident}} {
{%- for ty in types %}
{{ loop.index - 1 }}: {{ ty.ts_type() }};
{%- endfor %}
}
{% endif -%}
{%- when EnumVariantDeclaration::Named with { ident, types } %}
export interface {{type_variant}}_{{ident}} {
{%- for (id, ty) in types %}
{{ id }}: {{ ty.ts_type() }};
{%- endfor %}
}
{% else %}
{%- endmatch -%}
{% endfor %}
export module {{ident}} {
{%- for variant in variants -%}
{%- match variant -%}
{%- when EnumVariantDeclaration::Unit with { ident, value } %}
export const {{ident}}: {{type_variant}} = { tag: '{{ident}}' };
{%- when EnumVariantDeclaration::Unnamed with { ident, types } %}
{%- if types.len() == 1 %}
export const {{ident}} = (value: {{ variant.first_type().ts_type() }}): {{type_variant}} => ({ tag: '{{ident}}', value });
{%- else %}
export const {{ident}} = (
{%- for ty in types -%}
p{{loop.index - 1}}: {{ ty.ts_type() }},
{%- endfor -%}
): {{type_variant}} => ({ tag: '{{ident}}', value: [
{%- for ty in types -%}
p{{loop.index - 1}},
{%- endfor -%}
] });
{%- endif -%}
{%- when EnumVariantDeclaration::Named with { ident, types } %}
export const {{ident}} = (value: {{type_variant}}_{{ident}}): {{type_variant}} => ({ tag: '{{ident}}', value });
{%- endmatch -%}
{% endfor %}
}
export function write{{ident}}(value: {{ident}}, sinkOrBuf?: SinkOrBuf): Sink {
const sink = Sink.create(sinkOrBuf);
switch(value.tag) {
{%- for variant in variants %}
{%- let i = loop.index %}
case '{{variant.ident()}}':
writeU32({{loop.index - 1}}, sink);
{%- match variant -%}
{%- when EnumVariantDeclaration::Unit with { ident, value } %}
{%- when EnumVariantDeclaration::Unnamed with { ident, types } %}
{%- if types.len() == 1 %}
const val{{i}} = value as { value: {{ variant.first_type().ts_type() }} };
{{ variant.first_type().writer() }}(val{{i}}.value, sink);
{%- else %}
const val{{i}} = value as { value: {{type_variant}}_{{ident}} };
{%- for ty in types %}
{{ ty.writer() }}(val{{i}}.value[{{loop.index -1}}], sink);
{%- endfor %}
{%- endif -%}
{%- when EnumVariantDeclaration::Named with { ident, types } %}
const val{{i}} = value as { value: {{type_variant}}_{{ident}} };
{%- for (id, ty) in types %}
{{ ty.writer() }}(val{{i}}.value.{{id}}, sink);
{%- endfor -%}
{%- endmatch %}
break;
{%- endfor %}
default:
throw new Error(`'${(value as any).tag}' is invalid tag for enum '{{ident}}'`);
}
return sink;
}
export function read{{ident}}(sinkOrBuf: SinkOrBuf): {{ident}} {
const sink = Sink.create(sinkOrBuf);
const value = readU32(sink);
switch (value) {
{%- for variant in variants %}
case {{loop.index - 1}}:
{%- match variant -%}
{%- when EnumVariantDeclaration::Unit with { ident, value } %}
return {{type_variant}}.{{ident}};
{%- when EnumVariantDeclaration::Unnamed with { ident, types } %}
return {{type_variant}}.{{ident}}(
{%- for ty in types %}
{{ ty.reader() }}(sink),
{%- endfor %}
);
{%- when EnumVariantDeclaration::Named with { ident, types } %}
return {{type_variant}}.{{ident}}({
{%- for (id, ty) in types %}
{{ id }}: {{ ty.reader() }}(sink),
{%- endfor %}
});
{%- endmatch -%}
{%- endfor %}
default:
throw new Error(`'${value}' is invalid value for enum '{{ident}}'`);
}
}