Introduces Bytes class (#1019)

This introduces a new `Bytes` standard library class, for working with
binary data.

* Add Bytes class to the standard library
* Change CLI to eval `output.bytes`
* Change code generators to map Bytes to respective underlying type
* Add subscript and concat operator support
* Add binary encoding for Bytes
* Add PCF and Plist rendering for Bytes

Co-authored-by: Kushal Pisavadia <kushi.p@gmail.com>
This commit is contained in:
Daniel Chao
2025-06-11 16:23:55 -07:00
committed by GitHub
parent 3bd8a88506
commit e9320557b7
104 changed files with 2210 additions and 545 deletions
@@ -120,6 +120,7 @@ class KotlinCodeGeneratorTest {
any: Any
nonNull: NonNull
enum: Direction
bytes: Bytes
}
open class Other {
@@ -193,7 +194,6 @@ class KotlinCodeGeneratorTest {
@Test
fun testToString() {
val (_, propertyTypes) = instantiateOtherAndPropertyTypes()
assertThat(propertyTypes.toString())
.isEqualTo(
"""PropertyTypes(boolean=true, int=42, float=42.3, string=string, duration=5.min, """ +
@@ -204,7 +204,8 @@ class KotlinCodeGeneratorTest {
"""set2=[Other(name=pigeon)], map={1=one, 2=two}, map2={one=Other(name=pigeon), """ +
"""two=Other(name=pigeon)}, container={1=one, 2=two}, container2={one=Other(name=pigeon), """ +
"""two=Other(name=pigeon)}, other=Other(name=pigeon), regex=(i?)\w*, any=Other(name=pigeon), """ +
"""nonNull=Other(name=pigeon), enum=north)"""
"""nonNull=Other(name=pigeon), enum=north, """ +
"""bytes=[1, 2, 3, 4])"""
)
}
@@ -412,6 +413,7 @@ class KotlinCodeGeneratorTest {
assertThat(readProperty(propertyTypes, "regex")).isInstanceOf(Regex::class.java)
assertThat(readProperty(propertyTypes, "any")).isEqualTo(other)
assertThat(readProperty(propertyTypes, "nonNull")).isEqualTo(other)
assertThat(readProperty(propertyTypes, "bytes")).isEqualTo(byteArrayOf(1, 2, 3, 4))
}
private fun readProperty(receiver: Any, name: String): Any? {
@@ -571,6 +573,25 @@ class KotlinCodeGeneratorTest {
.contains("result = 31 * result + Objects.hashCode(this.name.pattern)")
}
@Test
fun `data class with ByteArray property has custom equals and hashCode methods`() {
val kotlinCode =
generateKotlinCode(
"""
module my.mod
class Foo {
bytes: Bytes
}
"""
.trimIndent()
)
assertThat(kotlinCode)
.contains("if (!this.bytes.contentEquals(other.bytes)) return false")
.contains("result = 31 * result + this.bytes.contentHashCode()")
}
@Test
fun `recursive types`() {
val kotlinCode =
@@ -2078,6 +2099,7 @@ class KotlinCodeGeneratorTest {
other,
other,
enumValue,
byteArrayOf(1, 2, 3, 4),
)
return other to propertyTypes
@@ -1,8 +1,10 @@
package my
import java.util.Arrays
import java.util.Objects
import kotlin.Any
import kotlin.Boolean
import kotlin.ByteArray
import kotlin.Double
import kotlin.Int
import kotlin.Long
@@ -46,7 +48,8 @@ object Mod {
open val regex: Regex,
open val any: Any?,
open val nonNull: Any,
open val enum: Direction
open val enum: Direction,
open val bytes: ByteArray
) {
open fun copy(
boolean: Boolean = this.boolean,
@@ -75,10 +78,11 @@ object Mod {
regex: Regex = this.regex,
any: Any? = this.any,
nonNull: Any = this.nonNull,
enum: Direction = this.enum
enum: Direction = this.enum,
bytes: ByteArray = this.bytes
): PropertyTypes = PropertyTypes(boolean, int, float, string, duration, durationUnit, dataSize,
dataSizeUnit, nullable, nullable2, pair, pair2, coll, coll2, list, list2, set, set2, map,
map2, container, container2, other, regex, any, nonNull, enum)
map2, container, container2, other, regex, any, nonNull, enum, bytes)
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -111,6 +115,7 @@ object Mod {
if (this.any != other.any) return false
if (this.nonNull != other.nonNull) return false
if (this.enum != other.enum) return false
if (!this.bytes.contentEquals(other.bytes)) return false
return true
}
@@ -143,11 +148,12 @@ object Mod {
result = 31 * result + Objects.hashCode(this.any)
result = 31 * result + Objects.hashCode(this.nonNull)
result = 31 * result + Objects.hashCode(this.enum)
result = 31 * result + this.bytes.contentHashCode()
return result
}
override fun toString(): String =
"""PropertyTypes(boolean=$boolean, int=$int, float=$float, string=$string, duration=$duration, durationUnit=$durationUnit, dataSize=$dataSize, dataSizeUnit=$dataSizeUnit, nullable=$nullable, nullable2=$nullable2, pair=$pair, pair2=$pair2, coll=$coll, coll2=$coll2, list=$list, list2=$list2, set=$set, set2=$set2, map=$map, map2=$map2, container=$container, container2=$container2, other=$other, regex=$regex, any=$any, nonNull=$nonNull, enum=$enum)"""
"""PropertyTypes(boolean=$boolean, int=$int, float=$float, string=$string, duration=$duration, durationUnit=$durationUnit, dataSize=$dataSize, dataSizeUnit=$dataSizeUnit, nullable=$nullable, nullable2=$nullable2, pair=$pair, pair2=$pair2, coll=$coll, coll2=$coll2, list=$list, list2=$list2, set=$set, set2=$set2, map=$map, map2=$map2, container=$container, container2=$container2, other=$other, regex=$regex, any=$any, nonNull=$nonNull, enum=$enum, bytes=${Arrays.toString(bytes)})"""
}
open class Other(