///|
let bcrypt_alphabet : Bytes = b"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

///|
fn bcrypt_base64_encode(bytes : BytesView, length : Int) -> String {
  let builder = StringBuilder(size_hint=(length * 4 + 2) / 3)
  let mut offset = 0
  while offset < length {
    let c1 = bytes[offset].to_int()
    offset += 1
    builder.write_char(bcrypt_alphabet[c1 >> 2].to_char())
    let mut c = (c1 & 0x03) << 4
    if offset >= length {
      builder.write_char(bcrypt_alphabet[c].to_char())
      break
    }
    let c2 = bytes[offset].to_int()
    offset += 1
    c = c | ((c2 & 0xf0) >> 4)
    builder.write_char(bcrypt_alphabet[c].to_char())
    c = (c2 & 0x0f) << 2
    if offset >= length {
      builder.write_char(bcrypt_alphabet[c].to_char())
      break
    }
    let c3 = bytes[offset].to_int()
    offset += 1
    c = c | ((c3 & 0xc0) >> 6)
    builder.write_char(bcrypt_alphabet[c].to_char())
    builder.write_char(bcrypt_alphabet[c3 & 0x3f].to_char())
  }
  builder.to_string()
}

///|
fn bcrypt_base64_decode(
  text : String,
  max_length : Int,
) -> Result[Bytes, BcryptError] {
  let out = Array::new(capacity=max_length)
  let mut offset = 0
  while offset < text.length() - 1 && out.length() < max_length {
    let c1 = bcrypt_base64_index(text[offset].to_int())
    let c2 = bcrypt_base64_index(text[offset + 1].to_int())
    if c1 < 0 || c2 < 0 {
      return Err(InvalidBase64)
    }
    offset += 2
    out.push(((c1 << 2) | ((c2 & 0x30) >> 4)).to_byte())
    if out.length() >= max_length || offset >= text.length() {
      break
    }
    let c3 = bcrypt_base64_index(text[offset].to_int())
    if c3 < 0 {
      return Err(InvalidBase64)
    }
    offset += 1
    out.push((((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2)).to_byte())
    if out.length() >= max_length || offset >= text.length() {
      break
    }
    let c4 = bcrypt_base64_index(text[offset].to_int())
    if c4 < 0 {
      return Err(InvalidBase64)
    }
    offset += 1
    out.push((((c3 & 0x03) << 6) | c4).to_byte())
  }
  if out.length() == max_length {
    Ok(Bytes::from_array(out.view()))
  } else {
    Err(InvalidBase64)
  }
}

///|
fn bcrypt_base64_all_valid(text : String) -> Bool {
  for i in 0.. Int {
  match code {
    46 => 0 // .
    47 => 1 // /
    65..=90 => code - 65 + 2
    97..=122 => code - 97 + 28
    48..=57 => code - 48 + 54
    _ => -1
  }
}