-
Notifications
You must be signed in to change notification settings - Fork 234
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for enums with associated data.
This commit adds support for enums variants having named data fields, in a style similar to records. It also attempts to expose both "plain" enums and the new data-bearing enums to target foreign languages in an idiomatic way. Unfortunately for us, WebIDL doesn't have native syntax for this kind of data. Fortunately for us, we can fake it by using anonymous special interface methods via a syntax like: ``` [Enum] interface EnumWithData { VariantName(type1 name1, type2 name2, ...); } ```
- Loading branch information
Showing
31 changed files
with
920 additions
and
166 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 77 additions & 8 deletions
85
uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,88 @@ | ||
{# | ||
// Kotlin's `enum class` constuct 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 {{ e.name()|class_name_kt }} { | ||
{% for variant in e.variants() %} | ||
{{ variant|enum_variant_kt }}{% if loop.last %};{% else %},{% endif %} | ||
{% endfor %} | ||
{% for variant in e.variants() -%} | ||
{{ variant.name()|enum_variant_kt }}{% if loop.last %};{% else %},{% endif %} | ||
{%- endfor %} | ||
|
||
companion object { | ||
internal fun lift(n: Int) = | ||
try { values()[n - 1] } | ||
internal fun lift(rbuf: RustBuffer.ByValue): {{ e.name()|class_name_kt }} { | ||
return liftFromRustBuffer(rbuf) { buf -> {{ e.name()|class_name_kt }}.read(buf) } | ||
} | ||
|
||
internal fun read(buf: ByteBuffer) = | ||
try { values()[buf.getInt() - 1] } | ||
catch (e: IndexOutOfBoundsException) { | ||
throw RuntimeException("invalid enum value, something is very wrong!!", e) | ||
} | ||
} | ||
|
||
internal fun lower(): RustBuffer.ByValue { | ||
return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) | ||
} | ||
|
||
internal fun write(buf: RustBufferBuilder) { | ||
buf.putInt(this.ordinal + 1) | ||
} | ||
} | ||
|
||
internal fun read(buf: ByteBuffer) = lift(buf.getInt()) | ||
{% else %} | ||
|
||
sealed class {{ e.name()|class_name_kt }} { | ||
{% for variant in e.variants() -%} | ||
{% if !variant.has_fields() -%} | ||
object {{ variant.name()|class_name_kt }} : {{ e.name()|class_name_kt }}() | ||
{% else -%} | ||
data class {{ variant.name()|class_name_kt }}( | ||
{% for field in variant.fields() -%} | ||
val {{ field.name()|var_name_kt }}: {{ field.type_()|type_kt}}{% if loop.last %}{% else %}, {% endif %} | ||
{% endfor -%} | ||
) : {{ e.name()|class_name_kt }}() | ||
{%- endif %} | ||
{% endfor %} | ||
|
||
companion object { | ||
internal fun lift(rbuf: RustBuffer.ByValue): {{ e.name()|class_name_kt }} { | ||
return liftFromRustBuffer(rbuf) { buf -> {{ e.name()|class_name_kt }}.read(buf) } | ||
} | ||
|
||
internal fun read(buf: ByteBuffer): {{ e.name()|class_name_kt }} { | ||
return when(buf.getInt()) { | ||
{%- for variant in e.variants() %} | ||
{{ loop.index }} -> {{ e.name()|class_name_kt }}.{{ variant.name()|class_name_kt }}{% if variant.has_fields() %}( | ||
{% for field in variant.fields() -%} | ||
{{ "buf"|read_kt(field.type_()) }}{% if loop.last %}{% else %},{% endif %} | ||
{% endfor -%} | ||
){%- endif -%} | ||
{%- endfor %} | ||
else -> throw RuntimeException("invalid enum value, something is very wrong!!") | ||
} | ||
} | ||
} | ||
|
||
internal fun lower() = this.ordinal + 1 | ||
internal fun lower(): RustBuffer.ByValue { | ||
return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) | ||
} | ||
|
||
internal fun write(buf: RustBufferBuilder) = buf.putInt(this.lower()) | ||
internal fun write(buf: RustBufferBuilder) { | ||
when(this) { | ||
{%- for variant in e.variants() %} | ||
is {{ e.name()|class_name_kt }}.{{ variant.name()|class_name_kt }} -> { | ||
buf.putInt({{ loop.index }}) | ||
{% for field in variant.fields() -%} | ||
{{ "(this.{})"|format(field.name())|write_kt("buf", field.type_()) }} | ||
{% endfor -%} | ||
} | ||
{%- endfor %} | ||
}.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } | ||
} | ||
} | ||
|
||
{% endif %} |
Oops, something went wrong.