///|
/// Convert a domain that is already plain ASCII without running the general
/// UTS #46 algorithm.
///
/// Returns the converted domain when every label is valid as written, so
/// that ToASCII and ToUnicode both reduce to lowercasing. Returns `None`
/// when the general algorithm must run: a non-ASCII character, a possible
/// A-label (`xn--`), or anything that might be an error. Errors are always
/// left to the general algorithm, so both paths report them identically.
fn ascii_fast_path(
  domain : String,
  use_std3_ascii_rules~ : Bool,
  check_hyphens~ : Bool,
  verify_dns_length~ : Bool,
) -> String? {
  let length = domain.length()
  if verify_dns_length && length > 253 {
    return None
  }
  let mut label_start = 0
  let mut has_uppercase = false
  for i in 0.. ()
      'A'..<='Z' => has_uppercase = true
      '.' => {
        guard is_plain_ascii_label(
          domain,
          label_start,
          i,
          check_hyphens~,
          verify_dns_length~,
        ) else {
          return None
        }
        label_start = i + 1
      }
      // Every other ASCII character is valid unless STD3 rules apply.
      unit => if use_std3_ascii_rules || unit >= 0x80 { return None }
    }
  }
  if label_start == length {
    // An empty final label is a trailing dot, which needs a label before it
    // and is rejected by the DNS length check.
    if label_start == 0 || verify_dns_length {
      return None
    }
  } else if !is_plain_ascii_label(
      domain,
      label_start,
      length,
      check_hyphens~,
      verify_dns_length~,
    ) {
    return None
  }
  Some(if has_uppercase { domain.to_lower() } else { domain })
}

///|
/// Check the label `domain[start:end]`, whose characters are known to be
/// valid ASCII, against the rules that depend on position and length.
fn is_plain_ascii_label(
  domain : String,
  start : Int32,
  end : Int32,
  check_hyphens~ : Bool,
  verify_dns_length~ : Bool,
) -> Bool {
  let length = end - start
  if length == 0 || (verify_dns_length && length > 63) {
    return false
  }
  if length >= 4 && domain[start + 2] == '-' && domain[start + 3] == '-' {
    // Hyphens in the third and fourth positions are either a violation or
    // the prefix of an A-label, which has to be decoded.
    if check_hyphens ||
      (domain[start] is ('x' | 'X') && domain[start + 1] is ('n' | 'N')) {
      return false
    }
  }
  !check_hyphens || (domain[start] != '-' && domain[end - 1] != '-')
}