or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

byte-order-operations.mdchannel-factories.mdchannel-interfaces.mdchannel-operations.mdcharacter-encoding.mdindex.mdobject-pooling.md
tile.json

byte-order-operations.mddocs/

Byte Order Operations

Utilities for byte order manipulation and bit-level operations for handling different endianness and extracting components from primitive types.

Capabilities

Byte Order Reversal

Reverse the byte order of primitive types to handle different endianness.

/** Reverse byte order of a Short (16-bit) */
expect fun Short.reverseByteOrder(): Short

/** Reverse byte order of an Int (32-bit) */
expect fun Int.reverseByteOrder(): Int

/** Reverse byte order of a Long (64-bit) */
expect fun Long.reverseByteOrder(): Long

/** Reverse byte order of a Float (32-bit) */
expect fun Float.reverseByteOrder(): Float

/** Reverse byte order of a Double (64-bit) */
expect fun Double.reverseByteOrder(): Double

/** Reverse byte order of an unsigned Short (16-bit) */
fun UShort.reverseByteOrder(): UShort

/** Reverse byte order of an unsigned Int (32-bit) */
fun UInt.reverseByteOrder(): UInt

/** Reverse byte order of an unsigned Long (64-bit) */
fun ULong.reverseByteOrder(): ULong

Usage Examples:

import io.ktor.utils.io.bits.*

fun byteOrderReversalExamples() {
    // Reverse signed integers
    val short: Short = 0x1234
    val reversedShort = short.reverseByteOrder() // 0x3412
    
    val int: Int = 0x12345678
    val reversedInt = int.reverseByteOrder() // 0x78563412
    
    val long: Long = 0x123456789ABCDEF0L
    val reversedLong = long.reverseByteOrder() // 0xF0DEBC9A78563412L
    
    // Reverse floating point numbers
    val float: Float = 3.14f
    val reversedFloat = float.reverseByteOrder()
    
    val double: Double = 2.718281828
    val reversedDouble = double.reverseByteOrder()
    
    // Reverse unsigned integers
    val uShort: UShort = 0x1234u
    val reversedUShort = uShort.reverseByteOrder() // 0x3412u
    
    val uInt: UInt = 0x12345678u
    val reversedUInt = uInt.reverseByteOrder() // 0x78563412u
    
    val uLong: ULong = 0x123456789ABCDEF0uL
    val reversedULong = uLong.reverseByteOrder() // 0xF0DEBC9A78563412uL
    
    println("Original short: 0x${short.toString(16)}")
    println("Reversed short: 0x${reversedShort.toString(16)}")
}

Byte Extraction

Extract individual bytes and components from larger primitive types.

/** Extract high byte from a Short */
val Short.highByte: Byte

/** Extract low byte from a Short */
val Short.lowByte: Byte

/** Extract high short from an Int */
val Int.highShort: Short

/** Extract low short from an Int */
val Int.lowShort: Short

/** Extract high int from a Long */
val Long.highInt: Int

/** Extract low int from a Long */
val Long.lowInt: Int

Usage Examples:

import io.ktor.utils.io.bits.*

fun byteExtractionExamples() {
    // Extract bytes from Short
    val shortValue: Short = 0x1234
    val highByte = shortValue.highByte // 0x12
    val lowByte = shortValue.lowByte   // 0x34
    
    println("Short 0x${shortValue.toString(16)}: high=0x${highByte.toUByte().toString(16)}, low=0x${lowByte.toUByte().toString(16)}")
    
    // Extract shorts from Int
    val intValue: Int = 0x12345678
    val highShort = intValue.highShort // 0x1234
    val lowShort = intValue.lowShort   // 0x5678
    
    println("Int 0x${intValue.toString(16)}: high=0x${highShort.toUShort().toString(16)}, low=0x${lowShort.toUShort().toString(16)}")
    
    // Extract ints from Long
    val longValue: Long = 0x123456789ABCDEF0L
    val highInt = longValue.highInt // 0x12345678
    val lowInt = longValue.lowInt   // 0x9ABCDEF0.toInt()
    
    println("Long 0x${longValue.toString(16)}: high=0x${highInt.toUInt().toString(16)}, low=0x${lowInt.toUInt().toString(16)}")
    
    // Reconstruct values
    val reconstructedShort = ((highByte.toInt() and 0xFF) shl 8) or (lowByte.toInt() and 0xFF)
    println("Reconstructed short: 0x${reconstructedShort.toString(16)} (original: 0x${shortValue.toString(16)})")
}

Endianness Handling

Common patterns for handling different byte orders in network protocols and file formats.

Usage Examples:

import io.ktor.utils.io.*
import io.ktor.utils.io.bits.*

suspend fun endiannessHandlingExamples() {
    // Reading big-endian data from a little-endian system
    val channel = ByteReadChannel(byteArrayOf(0x12, 0x34, 0x56, 0x78))
    
    val rawInt = channel.readInt()
    val bigEndianInt = if (isLittleEndian()) {
        rawInt.reverseByteOrder()
    } else {
        rawInt
    }
    
    println("Big-endian int: 0x${bigEndianInt.toString(16)}")
    
    // Writing little-endian data
    val writeChannel = ByteChannel()
    val value = 0x12345678
    val littleEndianValue = if (isBigEndian()) {
        value.reverseByteOrder()
    } else {
        value
    }
    
    writeChannel.writeInt(littleEndianValue)
    writeChannel.flush()
}

// Platform detection functions (examples)
fun isLittleEndian(): Boolean {
    val test = 0x12345678
    val bytes = ByteArray(4)
    bytes[0] = (test and 0xFF).toByte()
    bytes[1] = ((test shr 8) and 0xFF).toByte()
    bytes[2] = ((test shr 16) and 0xFF).toByte()
    bytes[3] = ((test shr 24) and 0xFF).toByte()
    
    return bytes[0] == 0x78.toByte()
}

fun isBigEndian(): Boolean = !isLittleEndian()

Protocol Implementation

Using byte order operations for implementing network protocols and binary formats.

Usage Examples:

import io.ktor.utils.io.*
import io.ktor.utils.io.bits.*

// Example: Reading a binary protocol header
suspend fun readProtocolHeader(channel: ByteReadChannel): ProtocolHeader {
    // Protocol uses big-endian format
    val magic = channel.readInt().let { 
        if (isLittleEndian()) it.reverseByteOrder() else it 
    }
    
    val version = channel.readShort().let {
        if (isLittleEndian()) it.reverseByteOrder() else it
    }
    
    val flags = channel.readShort() // Flags might not need byte order conversion
    val length = channel.readInt().let {
        if (isLittleEndian()) it.reverseByteOrder() else it
    }
    
    return ProtocolHeader(magic, version, flags, length)
}

// Example: Writing a binary protocol header
suspend fun writeProtocolHeader(channel: ByteWriteChannel, header: ProtocolHeader) {
    // Write in big-endian format
    val magic = if (isLittleEndian()) header.magic.reverseByteOrder() else header.magic
    val version = if (isLittleEndian()) header.version.reverseByteOrder() else header.version
    val length = if (isLittleEndian()) header.length.reverseByteOrder() else header.length
    
    channel.writeInt(magic)
    channel.writeShort(version)
    channel.writeShort(header.flags)
    channel.writeInt(length)
}

data class ProtocolHeader(
    val magic: Int,
    val version: Short,
    val flags: Short,
    val length: Int
)

Bit Manipulation Utilities

Advanced bit manipulation using byte order operations.

Usage Examples:

import io.ktor.utils.io.bits.*

fun bitManipulationExamples() {
    val value = 0x12345678
    
    // Extract individual bytes
    val byte0 = (value and 0xFF).toByte()           // 0x78
    val byte1 = ((value shr 8) and 0xFF).toByte()   // 0x56
    val byte2 = ((value shr 16) and 0xFF).toByte()  // 0x34
    val byte3 = ((value shr 24) and 0xFF).toByte()  // 0x12
    
    // Use high/low extraction
    val lowShort = value.lowShort   // 0x5678
    val highShort = value.highShort // 0x1234
    
    // Swap bytes within shorts
    val swappedLow = lowShort.reverseByteOrder()   // 0x7856
    val swappedHigh = highShort.reverseByteOrder() // 0x3412
    
    // Reconstruct with swapped bytes
    val reconstructed = (swappedHigh.toInt() shl 16) or (swappedLow.toInt() and 0xFFFF)
    println("Original: 0x${value.toString(16)}")
    println("Reconstructed: 0x${reconstructed.toString(16)}")
    
    // Working with floating point bit patterns
    val floatValue = 3.14f
    val floatBits = floatValue.toBits()
    val reversedBits = floatBits.reverseByteOrder()
    val reversedFloat = Float.fromBits(reversedBits)
    
    println("Float: $floatValue -> bits: 0x${floatBits.toString(16)} -> reversed: $reversedFloat")
}

Memory Layout Operations

Operations for working with memory layouts and packed structures.

Usage Examples:

import io.ktor.utils.io.*
import io.ktor.utils.io.bits.*

// Example: Packed structure with explicit byte order
suspend fun packedStructureExample() {
    val channel = ByteChannel()
    
    // Write packed structure (little-endian)
    val timestamp = System.currentTimeMillis()
    val value = 42.5f
    val count = 1000
    
    // Write as little-endian regardless of platform
    channel.writeLong(if (isBigEndian()) timestamp.reverseByteOrder() else timestamp)
    channel.writeFloat(if (isBigEndian()) value.reverseByteOrder() else value)
    channel.writeInt(if (isBigEndian()) count.reverseByteOrder() else count)
    
    channel.flush()
    
    // Read back the structure
    val readTimestamp = channel.readLong().let {
        if (isBigEndian()) it.reverseByteOrder() else it
    }
    val readValue = channel.readFloat().let {
        if (isBigEndian()) it.reverseByteOrder() else it
    }
    val readCount = channel.readInt().let {
        if (isBigEndian()) it.reverseByteOrder() else it
    }
    
    println("Read: timestamp=$readTimestamp, value=$readValue, count=$readCount")
}

// Helper for working with byte arrays and byte order
fun ByteArray.toIntLE(offset: Int = 0): Int {
    return ((this[offset + 3].toInt() and 0xFF) shl 24) or
           ((this[offset + 2].toInt() and 0xFF) shl 16) or
           ((this[offset + 1].toInt() and 0xFF) shl 8) or
           (this[offset].toInt() and 0xFF)
}

fun ByteArray.toIntBE(offset: Int = 0): Int {
    return ((this[offset].toInt() and 0xFF) shl 24) or
           ((this[offset + 1].toInt() and 0xFF) shl 16) or
           ((this[offset + 2].toInt() and 0xFF) shl 8) or
           (this[offset + 3].toInt() and 0xFF)
}

Byte Order Patterns

Network Byte Order (Big-Endian)

// Convert to network byte order
val networkInt = if (isLittleEndian()) value.reverseByteOrder() else value

// Convert from network byte order
val hostInt = if (isLittleEndian()) networkInt.reverseByteOrder() else networkInt

File Format Handling

// Little-endian file format
val fileValue = if (isBigEndian()) value.reverseByteOrder() else value

// Big-endian file format  
val fileValue = if (isLittleEndian()) value.reverseByteOrder() else value

Cross-Platform Compatibility

// Always write in specific byte order
fun writePortableInt(channel: ByteWriteChannel, value: Int, littleEndian: Boolean) {
    val ordered = when {
        littleEndian && isBigEndian() -> value.reverseByteOrder()
        !littleEndian && isLittleEndian() -> value.reverseByteOrder()
        else -> value
    }
    channel.writeInt(ordered)
}