diff options
Diffstat (limited to 'third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt')
-rw-r--r-- | third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt new file mode 100644 index 0000000000..d4c4a1684a --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt @@ -0,0 +1,110 @@ +{# +// 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() %} + +enum class {{ type_name }} { + {% for variant in e.variants() -%} + {{ variant|variant_name }}{% if loop.last %};{% else %},{% endif %} + {%- endfor %} + companion object +} + +public object {{ e|ffi_converter_name }}: FfiConverterRustBuffer<{{ type_name }}> { + override fun read(buf: ByteBuffer) = try { + {{ type_name }}.values()[buf.getInt() - 1] + } catch (e: IndexOutOfBoundsException) { + throw RuntimeException("invalid enum value, something is very wrong!!", e) + } + + override fun allocationSize(value: {{ type_name }}) = 4 + + override fun write(value: {{ type_name }}, buf: ByteBuffer) { + buf.putInt(value.ordinal + 1) + } +} + +{% else %} + +sealed class {{ type_name }}{% if contains_object_references %}: Disposable {% endif %} { + {% for variant in e.variants() -%} + {% if !variant.has_fields() -%} + object {{ variant|type_name(ci) }} : {{ type_name }}() + {% else -%} + data class {{ variant|type_name(ci) }}( + {% for field in variant.fields() -%} + val {{ field.name()|var_name }}: {{ field|type_name(ci) }}{% if loop.last %}{% else %}, {% endif %} + {% endfor -%} + ) : {{ type_name }}() { + 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 %} + companion object +} + +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 + ( + 4 + {%- for field in variant.fields() %} + + {{ field|allocation_size_fn }}(value.{{ field.name()|var_name }}) + {%- 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.{{ field.name()|var_name }}, buf) + {%- endfor %} + Unit + } + {%- endfor %} + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } +} + +{% endif %} |