diff --git a/build.gradle.kts b/build.gradle.kts index 32a0123..444cc12 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { val serialization_version = "1.6.5-SNAPSHOT" group = "net.sergeych" -version = "0.1.7" +version = "0.1.8-SNAPSHOT" repositories { mavenCentral() diff --git a/src/commonMain/kotlin/net.sergeych.bintools/ByteChunk.kt b/src/commonMain/kotlin/net.sergeych.bintools/ByteChunk.kt new file mode 100644 index 0000000..f3e9555 --- /dev/null +++ b/src/commonMain/kotlin/net.sergeych.bintools/ByteChunk.kt @@ -0,0 +1,80 @@ +package net.sergeych.bintools + +import kotlinx.serialization.Serializable +import kotlin.math.min +import kotlin.random.Random + +/** + * Bytes sequence with comparison, concatenation, and string representation, + * could be used as hash keys for pure binary values, etc. + */ +@Suppress("unused") +@Serializable +class ByteChunk(val data: UByteArray): Comparable { + + val size: Int get() = data.size + + /** + * Per-byte comparison also of different length. From two chunks + * of different size but equal beginning, the shorter is considered + * the smaller. + */ + override fun compareTo(other: ByteChunk): Int { + val limit = min(size, other.size) + for( i in 0 ..< limit) { + val own = data[i] + val their = other.data[i] + if( own < their) return -1 + else if( own > their) return 1 + } + if( size < other.size ) return -1 + if( size > other.size ) return 1 + return 0 + } + + /** + * Equal chunks means content equality. + */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is ByteChunk) return false + + return data contentEquals other.data + } + + /** + * Content-based hash code + */ + override fun hashCode(): Int { + return data.contentHashCode() + } + + /** + * hex representation of data + */ + override fun toString(): String = hex + + /** + * Hex encoded data + */ + val hex by lazy { data.encodeToHex() } + + /** + * human-readable dump + */ + val dump by lazy { data.toDump() } + + /** + * Concatenate two chunks and return new one + */ + operator fun plus(other: ByteChunk): ByteChunk = ByteChunk(data + other.data) + + companion object { + fun fromHex(hex: String): ByteChunk = ByteChunk(hex.decodeHex().asUByteArray()) + fun random(size: Int=16): ByteChunk = Random.nextBytes(size).asChunk() + } +} + +fun ByteArray.asChunk() = ByteChunk(this.asUByteArray()) +@Suppress("unused") +fun UByteArray.asChunk() = ByteChunk(this) \ No newline at end of file diff --git a/src/commonMain/kotlin/net.sergeych.bintools/simple_codecs.kt b/src/commonMain/kotlin/net.sergeych.bintools/simple_codecs.kt index 02b78fc..2bc409b 100644 --- a/src/commonMain/kotlin/net.sergeych.bintools/simple_codecs.kt +++ b/src/commonMain/kotlin/net.sergeych.bintools/simple_codecs.kt @@ -113,6 +113,8 @@ fun Collection.encodeToHex(separator: String = " "): String = joinToString fun ByteArray.toDump(wide: Boolean = false): String = toDumpLines(wide).joinToString("\n") +fun UByteArray.toDump(wide: Boolean = false): String = asByteArray().toDumpLines(wide).joinToString("\n") + fun ByteArray.toDumpLines(wide: Boolean = false): List { val lineSize = if (wide) 32 else 16