/*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* This source file is part of the Cangjie project, licensed under Apache-2.0
* with Runtime Library Exception.
*
* See https://cangjie-lang.cn/pages/LICENSE for license information.
*/
// The Cangjie API is in Beta. For details on its capabilities and limitations, please refer to the README file.
package std.binary
/**
* big-endian order interface
*
*/
public interface BigEndianOrder<T> {
/**
* @brief write a value of type T in big-endian order to the buffer byte array
* @param buffer, the target byte array
* @return the number of bytes written if the buffer length is sufficient, otherwise throws an exception
* @exception throws IndexOutOfBoundsException when the target length is insufficient
*/
func writeBigEndian(buffer: Array<Byte>): Int64
/**
* @brief read the value of type T in big-endian order from the buffer byte array
* @param buffer, the source byte array
* @return the value of type T
* @exception throws IndexOutOfBoundsException when the target length is insufficient
*/
static func readBigEndian(buffer: Array<Byte>): T
}
/**
* little-endian order interface
*
*/
public interface LittleEndianOrder<T> {
/**
* @brief write a value of type T in little-endian order to the buffer byte array
* @param buffer, the target byte array
* @return the number of bytes written if the buffer length is sufficient, otherwise throws an exception
* @exception throws IndexOutOfBoundsException when the target length is insufficient
*/
func writeLittleEndian(buffer: Array<Byte>): Int64
/**
* @brief read the value of type T in little-endian order from the buffer byte array
* @param buffer, the source byte array
* @return the value of type T
* @exception throws IndexOutOfBoundsException when the target length is insufficient
*/
static func readLittleEndian(buffer: Array<Byte>): T
}
/**
* @brief swap endian order interface
*
*/
public interface SwapEndianOrder<T> {
/**
* @brief reverse the byte order of T
* @return the value of type T
*/
func swapBytes(): T
}
extend UInt64 <: BigEndianOrder<UInt64> & LittleEndianOrder<UInt64> & SwapEndianOrder<UInt64> {
@OverflowWrapping
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
if (buffer.size < 8) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
buffer[0] = UInt8(this)
buffer[1] = UInt8(this >> 8)
buffer[2] = UInt8(this >> 16)
buffer[3] = UInt8(this >> 24)
buffer[4] = UInt8(this >> 32)
buffer[5] = UInt8(this >> 40)
buffer[6] = UInt8(this >> 48)
buffer[7] = UInt8(this >> 56)
return 8
}
@OverflowWrapping
public func writeBigEndian(buffer: Array<Byte>): Int64 {
if (buffer.size < 8) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
buffer[0] = UInt8(this >> 56)
buffer[1] = UInt8(this >> 48)
buffer[2] = UInt8(this >> 40)
buffer[3] = UInt8(this >> 32)
buffer[4] = UInt8(this >> 24)
buffer[5] = UInt8(this >> 16)
buffer[6] = UInt8(this >> 8)
buffer[7] = UInt8(this)
return 8
}
@OverflowWrapping
public static func readBigEndian(buffer: Array<Byte>): UInt64 {
if (buffer.size < 8) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return UInt64(buffer[7]) | UInt64(buffer[6]) << 8 | UInt64(buffer[5]) << 16 | UInt64(buffer[4]) << 24 |
UInt64(buffer[3]) << 32 | UInt64(buffer[2]) << 40 | UInt64(buffer[1]) << 48 | UInt64(buffer[0]) << 56
}
@OverflowWrapping
public static func readLittleEndian(buffer: Array<Byte>): UInt64 {
if (buffer.size < 8) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return UInt64(buffer[0]) | UInt64(buffer[1]) << 8 | UInt64(buffer[2]) << 16 | UInt64(buffer[3]) << 24 |
UInt64(buffer[4]) << 32 | UInt64(buffer[5]) << 40 | UInt64(buffer[6]) << 48 | UInt64(buffer[7]) << 56
}
public func swapBytes(): UInt64 {
return unsafe { CJ_Bswap64(this) }
}
}
extend Int64 <: BigEndianOrder<Int64> & LittleEndianOrder<Int64> & SwapEndianOrder<Int64> {
@OverflowWrapping
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
UInt64(this).writeLittleEndian(buffer)
}
@OverflowWrapping
public func writeBigEndian(buffer: Array<Byte>): Int64 {
UInt64(this).writeBigEndian(buffer)
}
@OverflowWrapping
public static func readBigEndian(buffer: Array<Byte>): Int64 {
if (buffer.size < 8) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return Int64(buffer[7]) | Int64(buffer[6]) << 8 | Int64(buffer[5]) << 16 | Int64(buffer[4]) << 24 |
Int64(buffer[3]) << 32 | Int64(buffer[2]) << 40 | Int64(buffer[1]) << 48 | Int64(buffer[0]) << 56
}
@OverflowWrapping
public static func readLittleEndian(buffer: Array<Byte>): Int64 {
if (buffer.size < 8) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return Int64(buffer[0]) | Int64(buffer[1]) << 8 | Int64(buffer[2]) << 16 | Int64(buffer[3]) << 24 |
Int64(buffer[4]) << 32 | Int64(buffer[5]) << 40 | Int64(buffer[6]) << 48 | Int64(buffer[7]) << 56
}
@OverflowWrapping
public func swapBytes(): Int64 {
var reversed = UInt64(this).swapBytes()
return Int64(reversed)
}
}
extend UInt32 <: BigEndianOrder<UInt32> & LittleEndianOrder<UInt32> & SwapEndianOrder<UInt32> {
@OverflowWrapping
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
if (buffer.size < 4) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
buffer[0] = UInt8(this)
buffer[1] = UInt8(this >> 8)
buffer[2] = UInt8(this >> 16)
buffer[3] = UInt8(this >> 24)
return 4
}
@OverflowWrapping
public func writeBigEndian(buffer: Array<Byte>): Int64 {
if (buffer.size < 4) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
buffer[0] = UInt8(this >> 24)
buffer[1] = UInt8(this >> 16)
buffer[2] = UInt8(this >> 8)
buffer[3] = UInt8(this)
return 4
}
@OverflowWrapping
public static func readBigEndian(buffer: Array<Byte>): UInt32 {
if (buffer.size < 4) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return UInt32(buffer[3]) | UInt32(buffer[2]) << 8 | UInt32(buffer[1]) << 16 | UInt32(buffer[0]) << 24
}
@OverflowWrapping
public static func readLittleEndian(buffer: Array<Byte>): UInt32 {
if (buffer.size < 4) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return UInt32(buffer[0]) | UInt32(buffer[1]) << 8 | UInt32(buffer[2]) << 16 | UInt32(buffer[3]) << 24
}
public func swapBytes(): UInt32 {
return unsafe { CJ_Bswap32(this) }
}
}
extend Int32 <: BigEndianOrder<Int32> & LittleEndianOrder<Int32> & SwapEndianOrder<Int32> {
@OverflowWrapping
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
UInt32(this).writeLittleEndian(buffer)
}
@OverflowWrapping
public func writeBigEndian(buffer: Array<Byte>): Int64 {
UInt32(this).writeBigEndian(buffer)
}
@OverflowWrapping
public static func readBigEndian(buffer: Array<Byte>): Int32 {
if (buffer.size < 4) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return Int32(buffer[3]) | Int32(buffer[2]) << 8 | Int32(buffer[1]) << 16 | Int32(buffer[0]) << 24
}
@OverflowWrapping
public static func readLittleEndian(buffer: Array<Byte>): Int32 {
if (buffer.size < 4) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return Int32(buffer[0]) | Int32(buffer[1]) << 8 | Int32(buffer[2]) << 16 | Int32(buffer[3]) << 24
}
@OverflowWrapping
public func swapBytes(): Int32 {
var reversed = UInt32(this).swapBytes()
return Int32(reversed)
}
}
extend UInt16 <: BigEndianOrder<UInt16> & LittleEndianOrder<UInt16> & SwapEndianOrder<UInt16> {
@OverflowWrapping
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
if (buffer.size < 2) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
buffer[0] = UInt8(this)
buffer[1] = UInt8(this >> 8)
return 2
}
@OverflowWrapping
public func writeBigEndian(buffer: Array<Byte>): Int64 {
if (buffer.size < 2) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
buffer[0] = UInt8(this >> 8)
buffer[1] = UInt8(this)
return 2
}
@OverflowWrapping
public static func readBigEndian(buffer: Array<Byte>): UInt16 {
if (buffer.size < 2) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return UInt16(buffer[1]) | UInt16(buffer[0]) << 8
}
@OverflowWrapping
public static func readLittleEndian(buffer: Array<Byte>): UInt16 {
if (buffer.size < 2) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return UInt16(buffer[0]) | UInt16(buffer[1]) << 8
}
public func swapBytes(): UInt16 {
return unsafe { CJ_Bswap16(this) }
}
}
extend Int16 <: BigEndianOrder<Int16> & LittleEndianOrder<Int16> & SwapEndianOrder<Int16> {
@OverflowWrapping
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
UInt16(this).writeLittleEndian(buffer)
}
@OverflowWrapping
public func writeBigEndian(buffer: Array<Byte>): Int64 {
UInt16(this).writeBigEndian(buffer)
}
@OverflowWrapping
public static func readBigEndian(buffer: Array<Byte>): Int16 {
if (buffer.size < 2) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return Int16(buffer[1]) | Int16(buffer[0]) << 8
}
@OverflowWrapping
public static func readLittleEndian(buffer: Array<Byte>): Int16 {
if (buffer.size < 2) {
throw IndexOutOfBoundsException("Buffer size(${buffer.size}) is too small.")
}
return Int16(buffer[0]) | Int16(buffer[1]) << 8
}
@OverflowWrapping
public func swapBytes(): Int16 {
var reversed = UInt16(this).swapBytes()
return Int16(reversed)
}
}
extend UInt8 <: BigEndianOrder<UInt8> & LittleEndianOrder<UInt8> & SwapEndianOrder<UInt8> {
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
if (!buffer.isEmpty()) {
buffer[0] = this
return 1
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
public func writeBigEndian(buffer: Array<Byte>): Int64 {
if (!buffer.isEmpty()) {
buffer[0] = this
return 1
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
public static func readBigEndian(buffer: Array<Byte>): UInt8 {
if (!buffer.isEmpty()) {
return buffer[0]
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
public static func readLittleEndian(buffer: Array<Byte>): UInt8 {
if (!buffer.isEmpty()) {
return buffer[0]
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
public func swapBytes(): UInt8 {
this
}
}
extend Int8 <: BigEndianOrder<Int8> & LittleEndianOrder<Int8> & SwapEndianOrder<Int8> {
@OverflowWrapping
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
if (!buffer.isEmpty()) {
buffer[0] = UInt8(this)
return 1
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
@OverflowWrapping
public func writeBigEndian(buffer: Array<Byte>): Int64 {
if (!buffer.isEmpty()) {
buffer[0] = UInt8(this)
return 1
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
@OverflowWrapping
public static func readBigEndian(buffer: Array<Byte>): Int8 {
if (!buffer.isEmpty()) {
return Int8(buffer[0])
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
@OverflowWrapping
public static func readLittleEndian(buffer: Array<Byte>): Int8 {
if (!buffer.isEmpty()) {
return Int8(buffer[0])
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
public func swapBytes(): Int8 {
this
}
}
extend Float64 <: BigEndianOrder<Float64> & LittleEndianOrder<Float64> {
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
let bits = this.toBits()
bits.writeLittleEndian(buffer)
}
public func writeBigEndian(buffer: Array<Byte>): Int64 {
let bits = this.toBits()
bits.writeBigEndian(buffer)
}
public static func readBigEndian(buffer: Array<Byte>): Float64 {
let bits = UInt64.readBigEndian(buffer)
return Float64.fromBits(bits)
}
public static func readLittleEndian(buffer: Array<Byte>): Float64 {
let bits = UInt64.readLittleEndian(buffer)
return Float64.fromBits(bits)
}
}
extend Float32 <: BigEndianOrder<Float32> & LittleEndianOrder<Float32> {
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
let bits = this.toBits()
bits.writeLittleEndian(buffer)
}
public func writeBigEndian(buffer: Array<Byte>): Int64 {
let bits = this.toBits()
bits.writeBigEndian(buffer)
}
public static func readBigEndian(buffer: Array<Byte>): Float32 {
let bits = UInt32.readBigEndian(buffer)
return Float32.fromBits(bits)
}
public static func readLittleEndian(buffer: Array<Byte>): Float32 {
let bits = UInt32.readLittleEndian(buffer)
return Float32.fromBits(bits)
}
}
extend Float16 <: BigEndianOrder<Float16> & LittleEndianOrder<Float16> {
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
let bits = this.toBits()
bits.writeLittleEndian(buffer)
}
public func writeBigEndian(buffer: Array<Byte>): Int64 {
let bits = this.toBits()
bits.writeBigEndian(buffer)
}
public static func readBigEndian(buffer: Array<Byte>): Float16 {
let bits = UInt16.readBigEndian(buffer)
return Float16.fromBits(bits)
}
public static func readLittleEndian(buffer: Array<Byte>): Float16 {
let bits = UInt16.readLittleEndian(buffer)
return Float16.fromBits(bits)
}
}
extend Bool <: BigEndianOrder<Bool> & LittleEndianOrder<Bool> {
public func writeLittleEndian(buffer: Array<Byte>): Int64 {
if (!buffer.isEmpty()) {
buffer[0] = if (this) {
1
} else {
0
}
return 1
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
public func writeBigEndian(buffer: Array<Byte>): Int64 {
if (!buffer.isEmpty()) {
buffer[0] = if (this) {
1
} else {
0
}
return 1
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
public static func readBigEndian(buffer: Array<Byte>): Bool {
if (!buffer.isEmpty()) {
return buffer[0] != 0
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
public static func readLittleEndian(buffer: Array<Byte>): Bool {
if (!buffer.isEmpty()) {
return buffer[0] != 0
}
throw IllegalArgumentException("Buffer too small: need at least 1 byte.")
}
}
foreign func CJ_Bswap64(n: UInt64): UInt64
foreign func CJ_Bswap32(n: UInt32): UInt32
foreign func CJ_Bswap16(n: UInt16): UInt16