///|
/// Resolve byte specs against the selected representation length.
pub fn resolve_byte_ranges(
  request : RangeRequest,
  representation_length : Int64,
) -> Result[ResolvedRangeSet, RangeError] {
  if representation_length < 0L {
    return Err(
      range_error(
        Resolve,
        InvalidRepresentationLength,
        0,
        "representation length cannot be negative",
      ),
    )
  }
  if !request.unit().is_bytes() {
    return Err(
      range_error(
        Resolve,
        UnsupportedRangeUnit,
        0,
        "only bytes ranges have defined resolution semantics",
      ),
    )
  }
  let resolved : Array[ConcreteRange] = []
  let mut unsatisfiable = 0
  let specs = request.specs()
  for spec in specs {
    match resolve_one(spec, representation_length) {
      Some(range) => resolved.push(range)
      None => unsatisfiable = unsatisfiable + 1
    }
  }
  Ok(resolved_range_set(resolved, unsatisfiable, specs.length()))
}

///|
fn resolve_one(spec : ByteRangeSpec, length : Int64) -> ConcreteRange? {
  if length <= 0L {
    return None
  }
  match spec {
    Closed(first, requested_last) => {
      if first >= length {
        return None
      }
      let last = if requested_last >= length {
        length - 1L
      } else {
        requested_last
      }
      Some(concrete_range(first, last))
    }
    OpenEnded(first) =>
      if first >= length {
        None
      } else {
        Some(concrete_range(first, length - 1L))
      }
    Suffix(suffix_length) => {
      if suffix_length <= 0L {
        return None
      }
      let selected = if suffix_length >= length {
        length
      } else {
        suffix_length
      }
      Some(concrete_range(length - selected, length - 1L))
    }
  }
}