///|
/// A half-open byte range containing differences between two exports.
pub(all) struct Difference {
  offset : UInt64
  length : UInt64
}

///|
/// Compare a range from two NBD clients, returning exact contiguous differing bytes.
/// Sources must remain stable throughout the comparison. This scans all requested
/// bytes and raises when the result limit is exceeded rather than silently truncating.
pub async fn compare_ranges(
  left : Client,
  right : Client,
  offset : UInt64,
  length : UInt64,
  max_ranges~ : Int32 = 16384,
) -> Array[Difference] {
  if max_ranges <= 0 ||
    max_ranges > 1048576 ||
    offset > left.size ||
    offset > right.size ||
    length > left.size - offset ||
    length > right.size - offset {
    raise InvalidArgument("invalid comparison range or range limit")
  }
  let minimum = if left.min_block > right.min_block {
    left.min_block
  } else {
    right.min_block
  }
  let maximum = if left.max_block < right.max_block {
    left.max_block
  } else {
    right.max_block
  }
  if maximum < minimum ||
    offset % minimum.to_uint64() != 0UL ||
    length % minimum.to_uint64() != 0UL {
    raise InvalidArgument("comparison range violates block alignment")
  }
  let budget = if maximum < 1048576U { maximum } else { 1048576U }
  let chunk_size = if budget < minimum {
    minimum
  } else {
    budget - budget % minimum
  }
  let end = offset + length
  let ranges : Array[Difference] = []
  let mut current : UInt64? = None
  let mut position = offset
  while position < end {
    let remaining = end - position
    let count = if remaining < chunk_size.to_uint64() {
      remaining.to_int()
    } else {
      chunk_size.reinterpret_as_int()
    }
    let a = left.read_at(position, count)
    let b = right.read_at(position, count)
    for i in 0.. {
            if ranges.length() >= max_ranges {
              raise LimitExceeded("difference range limit exceeded")
            }
            ranges.push({ offset: start, length: here - start, })
            current = None
          }
          None => ()
        }
      }
    }
    position += count.to_uint64()
  }
  match current {
    Some(start) => {
      if ranges.length() >= max_ranges {
        raise LimitExceeded("difference range limit exceeded")
      }
      ranges.push({ offset: start, length: end - start, })
    }
    None => ()
  }
  ranges
}