///|
/// Writes a 32-bit signed integer into an Array[Byte] starting at offset in Big-Endian format.
pub fn set_int32(bytes : Array[Byte], offset : Int, value : Int) -> Unit {
  bytes[offset] = ((value >> 24) & 0xff).to_byte()
  bytes[offset + 1] = ((value >> 16) & 0xff).to_byte()
  bytes[offset + 2] = ((value >> 8) & 0xff).to_byte()
  bytes[offset + 3] = (value & 0xff).to_byte()
}

///|
/// Reads a 32-bit signed integer from Bytes starting at offset in Big-Endian format.
pub fn get_int32(bytes : Bytes, offset : Int) -> Int {
  let b0 = bytes[offset].to_int()
  let b1 = bytes[offset + 1].to_int()
  let b2 = bytes[offset + 2].to_int()
  let b3 = bytes[offset + 3].to_int()
  (b0 << 24) | (b1 << 16) | (b2 << 8) | b3
}

///|
/// Writes a 64-bit signed integer into an Array[Byte] starting at offset in Big-Endian format.
pub fn set_int64(bytes : Array[Byte], offset : Int, value : Int64) -> Unit {
  bytes[offset] = ((value >> 56).to_int() & 0xff).to_byte()
  bytes[offset + 1] = ((value >> 48).to_int() & 0xff).to_byte()
  bytes[offset + 2] = ((value >> 40).to_int() & 0xff).to_byte()
  bytes[offset + 3] = ((value >> 32).to_int() & 0xff).to_byte()
  bytes[offset + 4] = ((value >> 24).to_int() & 0xff).to_byte()
  bytes[offset + 5] = ((value >> 16).to_int() & 0xff).to_byte()
  bytes[offset + 6] = ((value >> 8).to_int() & 0xff).to_byte()
  bytes[offset + 7] = (value.to_int() & 0xff).to_byte()
}

///|
/// Reads a 64-bit signed integer from Bytes starting at offset in Big-Endian format.
pub fn get_int64(bytes : Bytes, offset : Int) -> Int64 {
  let b0 = bytes[offset].to_int().to_int64()
  let b1 = bytes[offset + 1].to_int().to_int64()
  let b2 = bytes[offset + 2].to_int().to_int64()
  let b3 = bytes[offset + 3].to_int().to_int64()
  let b4 = bytes[offset + 4].to_int().to_int64()
  let b5 = bytes[offset + 5].to_int().to_int64()
  let b6 = bytes[offset + 6].to_int().to_int64()
  let b7 = bytes[offset + 7].to_int().to_int64()
  (b0 << 56) |
  (b1 << 48) |
  (b2 << 40) |
  (b3 << 32) |
  (b4 << 24) |
  (b5 << 16) |
  (b6 << 8) |
  b7
}

///| FNV-1a 32-bit checksum implementation for Array[Byte].

///|
/// Computes the hash for a slice of bytes from offset to offset + len.
pub fn fnv1a(bytes : Array[Byte], offset : Int, len : Int) -> Int {
  let mut hash = -2128831035 // FNV offset basis: 2166136261 (signed: -2128831035)
  for i = 0; i < len; i = i + 1 {
    hash = hash ^ bytes[offset + i].to_int()
    hash = hash * 16777619 // FNV prime: 16777619
  }
  hash
}

///| FNV-1a 32-bit checksum implementation for Bytes.

///|
/// Computes the hash for a slice of bytes from offset to offset + len.
pub fn fnv1a_bytes(bytes : Bytes, offset : Int, len : Int) -> Int {
  let mut hash = -2128831035
  for i = 0; i < len; i = i + 1 {
    hash = hash ^ bytes[offset + i].to_int()
    hash = hash * 16777619
  }
  hash
}

///|
/// Converts a String to UTF-8/ASCII Bytes.
pub fn string_to_bytes(s : String) -> Bytes {
  let len = s.length()
  let arr = Array::make(len, (0).to_byte())
  for i = 0; i < len; i = i + 1 {
    arr[i] = s[i].to_int().to_byte()
  }
  Bytes::from_array(arr)
}

///|
/// Converts UTF-8/ASCII Bytes to a String.
pub fn bytes_to_string(bytes : Bytes) -> String {
  let builder = StringBuilder::new()
  let len = bytes.length()
  for i = 0; i < len; i = i + 1 {
    match bytes[i].to_int().to_char() {
      Some(c) => builder.write_char(c)
      None => builder.write_char('?')
    }
  }
  builder.to_string()
}