///|
/// Return the total width of cpdftoc's alternating `Font`/`Text` run list.
pub fn pdf_toc_width_of_runs(
  runs : ArrayView[PdfTypeElement],
) -> Double raise @core.PdfError {
  let mut width = 0.0
  let mut index = 0
  while index < runs.length() {
    guard index + 1 < runs.length() else { raise SoftError("width_of_runs") }
    match (runs[index], runs[index + 1]) {
      (PdfTypeFont(_, font, font_size), PdfTypeText(text)) => {
        width += pdf_toc_width_of_font_text(font, font_size, text)
        index += 2
      }
      _ => raise SoftError("width_of_runs")
    }
  }
  width
}

///|
/// Shorten the final text run to fit `max_width`, appending `...` if shortened.
///
/// This intentionally mirrors cpdf's narrow helper: only the final `Font`/`Text`
/// pair is trimmed and measured.
pub fn pdf_toc_shorten_text(
  fontpack : PdfFontPack,
  font_size : Double,
  max_width : Double,
  runs : ArrayView[PdfTypeElement],
) -> Array[PdfTypeElement] raise @core.PdfError {
  let output = runs.to_owned()
  let mut shortened = false
  let mut done = false
  while !done {
    match pdf_toc_last_text_width(output) {
      Some((text_index, _, width)) if width > max_width =>
        if pdf_toc_trim_last_text_once(output, text_index) {
          shortened = true
        } else {
          done = true
        }
      _ => done = true
    }
  }
  if shortened {
    let ellipsis = pdf_toc_ellipsis_run(fontpack, font_size)
    pdf_toc_append_elements(output, ellipsis)
  }
  output
}

///|
/// Build cpdftoc's dot-leader run for an available horizontal space.
pub fn pdf_toc_make_dots(
  space : Double,
  fontpack : PdfFontPack,
  font_size : Double,
) -> Array[PdfTypeElement] raise @core.PdfError {
  let dot_runs = pdf_toc_dot_run(fontpack, font_size)
  let dot_width = pdf_toc_width_of_runs(dot_runs)
  let raw_count = (space / dot_width).floor().to_int()
  let count = if raw_count < 0 { 0 } else { raw_count }
  let output : Array[PdfTypeElement] = [
    PdfTypeHGlue(space - dot_width * count.to_double()),
  ]
  for _ in 0..