///|
fn packed_projection(
  tables : Array[Table],
  targets : Array[Table],
) -> Array[TableStep] {
  let table = tables[0]
  let target = targets[0]
  if target.rows.is_empty() ||
    table.rows.length() % target.rows.length() != 0 ||
    targets.any(t => t.columns != target.columns) ||
    tables.any(t => t.columns != table.columns) {
    return []
  }
  let size = table.rows.length() / target.rows.length()
  let width = table.columns.length()
  if size < 2 || size > 64 || width * size > 64 {
    return []
  }
  for k, t in tables {
    if t.rows.length() != targets[k].rows.length() * size {
      return []
    }
  }
  let names : Array[String] = []
  for j in 0.. Array[Array[TableStep]] {
  let plans : Array[Array[TableStep]] = []
  let width = table.columns.length()
  if width == 1 &&
    !table.rows.is_empty() &&
    !target.rows.is_empty() &&
    target.columns.length() <= 16 {
    let labels = target.rows[0]
    for sep in separators {
      let first = table.rows[0][0].split(sep).map(s => s.to_owned()).collect()
      if first.length() != 2 ||
        first[0] != labels[0] ||
        !table.rows.all(r => r[0].split(sep).count() == 2) {
        continue
      }
      let key = "__loom_key"
      let value = "__loom_value"
      let context = "context_" + value
      let marker = Equals(Field(0), Literal(first[0]))
      let columns = generic_columns(target.columns.length())
      let header = All(
        Array::makei(target.columns.length(), i => {
          if i == 0 {
            Empty(Field(0))
          } else {
            Equals(Field(i), Literal(labels[i]))
          }
        }),
      )
      let outputs = target.columns.mapi((i, name) => OutputField::{
        name,
        expression: if i == 0 {
          If(header, Literal(first[0]), Field(0))
        } else {
          Field(i)
        },
      })
      plans.push([
        SplitColumn(table.columns[0], sep, [key, value]),
        CarryContext(marker, [value]),
        PivotGrid([context], key, value),
        MapRows({ columns, outputs, }),
      ])
    }
  }
  if width == 1 &&
    !table.rows.is_empty() &&
    target.columns.length() >= 2 &&
    target.rows.length() % table.rows.length() == 0 {
    let values = target.rows.length() / table.rows.length()
    let keys = target.columns.length() - 1
    let parts = keys + values
    if values >= 2 && parts <= 16 {
      for sep in separators {
        if table.rows.all(r => r[0].split(sep).count() == parts) {
          let names = Array::makei(parts, i => "__loom_part_" + i.to_string())
          let key_names = names[:keys].to_owned()
          plans.push([
            SplitColumn(table.columns[0], sep, names),
            Fold(key_names, names[keys:].to_owned(), "__loom_value"),
            Select(key_names + ["__loom_value"], target.columns),
          ])
        }
      }
    }
  }
  let wanted : Map[String, Bool] = Map([])
  for row in target.rows {
    for value in row {
      wanted[value] = true
    }
  }
  let relevant : Array[String] = []
  for i, name in table.columns {
    if table.rows.any(row => !row[i].is_empty() && wanted.contains(row[i])) {
      relevant.push(name)
    }
  }
  for n in 1..= 3 {
    for variable in 0.. {
          n != table.columns[variable] && n != table.columns[value]
        })
        if !keys.is_empty() &&
          keys.any(name => {
            let i = column_index(table, name) catch { _ => return false }
            table.rows.any(row => row[i].is_empty())
          }) {
          plans.push([
            FillDown(keys),
            PivotGrid(keys, table.columns[variable], table.columns[value]),
          ])
        }
      }
    }
  }
  for n in 0.. {
          values.all(name => {
            let i = column_index(table, name) catch { _ => return false }
            row[i].split(sep).count() == 2
          })
        }) {
        continue
      }
      let value_name = "__loom_value"
      let label = "__loom_label"
      let payload = "__loom_payload"
      if keys.contains(value_name) ||
        keys.contains(label) ||
        keys.contains(payload) {
        continue
      }
      plans.push([
        Fold(keys, values, value_name),
        SplitColumn(value_name, sep, [label, payload]),
        PivotGrid(keys, label, payload),
      ])
    }
  }
  plans
}