///|
fn unicode_string_char(code : Int, upper : Bool) -> Int {
  let mut first = 0
  let mut last = unicode_string_ranges.length()
  while first < last {
    let middle = first + (last - first) / 2
    let (low, high, up, down) = unicode_string_ranges[middle]
    if code < low {
      last = middle
    } else if code > high {
      first = middle + 1
    } else {
      let delta = if upper { up } else { down }
      if delta == 0x110000 {
        return low + (code - low) / 2 * 2 + (if upper { 0 } else { 1 })
      }
      return code + delta
    }
  }
  code
}

///|
fn unicode_string_case(text : String, upper : Bool) -> String {
  // Retain the core library's fast ASCII conversion. Its string case APIs
  // leave non-ASCII unchanged, so Unicode uses our pinned simple mapping.
  if text.iter().all(c => c.to_int() < 128) {
    return if upper { text.to_upper() } else { text.to_lower() }
  }
  let result = StringBuilder()
  for c in text.iter() {
    let mapped = if c.to_int() < 128 {
      if upper {
        c.to_ascii_uppercase().to_int()
      } else {
        c.to_ascii_lowercase().to_int()
      }
    } else {
      unicode_string_char(c.to_int(), upper)
    }
    result.write_char(mapped.unsafe_to_char())
  }
  result.to_string()
}