-
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
30 changed files
with
873 additions
and
158 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
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
93 changes: 84 additions & 9 deletions
93
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,94 @@ | ||
enum class {{ e.name()|class_name_kt }} { | ||
{% for variant in e.variants() %} | ||
{{ variant|enum_variant_kt }}{% if loop.last %};{% else %},{% endif %} | ||
{# | ||
// 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.has_associated_data() %} | ||
|
||
sealed class {{ e.name()|class_name_kt }} { | ||
{% for variant in e.variants() -%} | ||
class {{ variant.name()|class_name_kt }}({% if variant.has_fields() %} | ||
{% for field in variant.fields() -%} | ||
val {{ field.name()|var_name_kt }}: {{ field.type_()|type_kt}}{% if loop.last %}{% else %}, {% endif %} | ||
{% endfor -%} | ||
{%- endif %}) : {{ e.name()|class_name_kt }}() { | ||
override fun write(buf: RustBufferBuilder) { | ||
buf.putInt({{ loop.index }}) | ||
{% for field in variant.fields() -%} | ||
{{ "(this.{})"|format(field.name())|write_kt("buf", field.type_()) }} | ||
{% endfor -%} | ||
} | ||
override fun equals(other: Any?) : Boolean = | ||
if (other is {{ e.name()|class_name_kt }}.{{ variant.name()|class_name_kt }}) { | ||
{% if variant.has_fields() -%} | ||
{% for field in variant.fields() -%} | ||
{{ field.name()|var_name_kt }} == other.{{ field.name()|var_name_kt }}{% if loop.last %}{% else %} && {% endif -%} | ||
{% endfor -%} | ||
{% else -%} | ||
true | ||
{%- endif %} | ||
} else { | ||
false | ||
} | ||
} | ||
{% 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): {{ 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(): RustBuffer.ByValue { | ||
return lowerIntoRustBuffer(this, {v, buf -> v.write(buf)}) | ||
} | ||
|
||
internal open fun write(buf: RustBufferBuilder) { | ||
throw RuntimeException("enum variant should have overridden `write` method, something is very wrong!!") | ||
} | ||
} | ||
|
||
{% else %} | ||
|
||
enum class {{ e.name()|class_name_kt }} { | ||
{% for variant in e.variants() -%} | ||
{{ variant.name()|enum_variant_kt }}{% if loop.last %};{% else %},{% 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) = | ||
try { values()[buf.getInt() - 1] } | ||
catch (e: IndexOutOfBoundsException) { | ||
throw RuntimeException("invalid enum value, something is very wrong!!", e) | ||
} | ||
|
||
internal fun read(buf: ByteBuffer) = lift(buf.getInt()) | ||
} | ||
|
||
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) { | ||
buf.putInt(this.ordinal + 1) | ||
} | ||
} | ||
|
||
{% endif %} |
Oops, something went wrong.