///|
fn validate_input(
  rects : ArrayView[Rect],
  options : PackOptions,
) -> Result[Unit, PackError] {
  if options.bin.width <= 0 || options.bin.height <= 0 {
    return Err(InvalidBin(width=options.bin.width, height=options.bin.height))
  }
  if options.padding.outer < 0 || options.padding.inner < 0 {
    return Err(
      InvalidPadding(outer=options.padding.outer, inner=options.padding.inner),
    )
  }
  if options.padding.outer * 2 >= options.bin.width ||
    options.padding.outer * 2 >= options.bin.height {
    return Err(
      InvalidPadding(outer=options.padding.outer, inner=options.padding.inner),
    )
  }
  for rect in rects {
    if rect.id.is_empty() || rect.width <= 0 || rect.height <= 0 {
      return Err(InvalidRect(id=rect.id, width=rect.width, height=rect.height))
    }
  }
  match maybe_duplicate_id(rects) {
    Some(id) => Err(DuplicateId(id~))
    None => Ok(())
  }
}

///|
/// Validate a produced or externally assembled layout.
pub fn validate_layout(layout : Layout) -> Result[Unit, PackError] {
  if layout.bin.width <= 0 || layout.bin.height <= 0 {
    return Err(InvalidBin(width=layout.bin.width, height=layout.bin.height))
  }
  match maybe_duplicate_placement(layout.placements) {
    Some(id) => return Err(DuplicateId(id~))
    None => ()
  }
  for placed in layout.placements {
    if placed.width <= 0 ||
      placed.height <= 0 ||
      placed.x < 0 ||
      placed.y < 0 ||
      placed.x + placed.width > layout.bin.width ||
      placed.y + placed.height > layout.bin.height {
      return Err(OutOfBounds(id=placed.id))
    }
  }
  for i in 0..