1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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 %}
|