{# // Kotlin's `enum class` construct doesn't support variants with associated data, // but is a little nicer for consumers than its `sealed class` enum pattern. // So, we switch here, using `enum class` for enums with no associated data // and `sealed class` for the general case. #} {%- if e.is_flat() %} {%- call kt::docstring(e, 0) %} {% match e.variant_discr_type() %} {% when None %} enum class {{ type_name }} { {% for variant in e.variants() -%} {%- call kt::docstring(variant, 4) %} {{ variant|variant_name }}{% if loop.last %};{% else %},{% endif %} {%- endfor %} {% for meth in e.methods() -%} {%- call kt::func_decl("", meth, 4) %} {% endfor %} {%- let uniffi_trait_methods = e.uniffi_trait_methods() %} {%- call kt::uniffi_trait_impls(uniffi_trait_methods) %} companion object } {% when Some(variant_discr_type) %} enum class {{ type_name }}(val value: {{ variant_discr_type|type_name(ci) }}) { {% for variant in e.variants() -%} {%- call kt::docstring(variant, 4) %} {{ variant|variant_name }}({{ e|variant_discr_literal(loop.index0) }}){% if loop.last %};{% else %},{% endif %} {%- endfor %} {% for meth in e.methods() -%} {%- call kt::func_decl("", meth, 4) %} {% endfor %} {%- let uniffi_trait_methods = e.uniffi_trait_methods() %} {%- call kt::uniffi_trait_impls(uniffi_trait_methods) %} companion object } {% endmatch %} /** * @suppress */ public object {{ e|ffi_converter_name }}: FfiConverterRustBuffer<{{ type_name }}> { override fun read(buf: ByteBuffer) = try { {% if config.use_enum_entries() %} {{ type_name }}.entries[buf.getInt() - 1] {% else -%} {{ type_name }}.values()[buf.getInt() - 1] {%- endif %} } catch (e: IndexOutOfBoundsException) { throw RuntimeException("invalid enum value, something is very wrong!!", e) } override fun allocationSize(value: {{ type_name }}) = 4UL override fun write(value: {{ type_name }}, buf: ByteBuffer) { buf.putInt(value.ordinal + 1) } } {% else %} {%- call kt::docstring(e, 0) %} sealed class {{ type_name }}{% if contains_object_references %}: Disposable {% endif %} {%- let uniffi_trait_methods = e.uniffi_trait_methods() -%} {%- if uniffi_trait_methods.ord_cmp.is_some() -%} {% if contains_object_references %}, {% else %} : {% endif %}Comparable<{{ type_name }}> {%- endif %} { {% for variant in e.variants() -%} {%- call kt::docstring(variant, 4) %} {% if !variant.has_fields() -%} object {{ variant|type_name(ci) }} : {{ type_name }}() {% else -%} data class {{ variant|type_name(ci) }}( {%- for field in variant.fields() -%} {%- call kt::docstring(field, 8) %} val {% call kt::field_name(field, loop.index) %}: {{ field|qualified_type_name(ci, config) }} {%- if let Some(default) = field.default_value() %} = {{ default|render_default(field, ci) }} {% endif %} {%- if loop.last %}{% else %}, {% endif %} {%- endfor -%} ) : {{ type_name }}() {# we need uniffi trait methods on each variant's data-class #} {%- let uniffi_trait_methods = e.uniffi_trait_methods() %} {%- if uniffi_trait_methods.ord_cmp.is_some() %} , Comparable<{{ type_name }}> {%- endif %} { {% call kt::uniffi_trait_impls(uniffi_trait_methods) %} companion object } {%- endif %} {% endfor %} {% if contains_object_references %} @Suppress("UNNECESSARY_SAFE_CALL") // codegen is much simpler if we unconditionally emit safe calls here override fun destroy() { when(this) { {%- for variant in e.variants() %} is {{ type_name }}.{{ variant|type_name(ci) }} -> { {%- if variant.has_fields() %} {% call kt::destroy_fields(variant) %} {% else -%} // Nothing to destroy {%- endif %} } {%- endfor %} }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } {% endif %} {# We also need to put methods on the object to support variants with no data. We could maybe optimize this so only write when no-data variants actually exist? #} {% for meth in e.methods() -%} {%- call kt::func_decl("", meth, 4) %} {% endfor %} {%- call kt::uniffi_trait_impls(uniffi_trait_methods) %} companion object } /** * @suppress */ public object {{ e|ffi_converter_name }} : FfiConverterRustBuffer<{{ type_name }}>{ override fun read(buf: ByteBuffer): {{ type_name }} { return when(buf.getInt()) { {%- for variant in e.variants() %} {{ loop.index }} -> {{ type_name }}.{{ variant|type_name(ci) }}{% if variant.has_fields() %}( {% for field in variant.fields() -%} {{ field|read_fn }}(buf), {% endfor -%} ){%- endif -%} {%- endfor %} else -> throw RuntimeException("invalid enum value, something is very wrong!!") } } override fun allocationSize(value: {{ type_name }}) = when(value) { {%- for variant in e.variants() %} is {{ type_name }}.{{ variant|type_name(ci) }} -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( 4UL {%- for field in variant.fields() %} + {{ field|allocation_size_fn }}(value.{%- call kt::field_name(field, loop.index) -%}) {%- endfor %} ) } {%- endfor %} } override fun write(value: {{ type_name }}, buf: ByteBuffer) { when(value) { {%- for variant in e.variants() %} is {{ type_name }}.{{ variant|type_name(ci) }} -> { buf.putInt({{ loop.index }}) {%- for field in variant.fields() %} {{ field|write_fn }}(value.{%- call kt::field_name(field, loop.index) -%}, buf) {%- endfor %} Unit } {%- endfor %} }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } } } {% endif %}