///|
fn gen_valid_campaign_call_topology_config() -> GenValidConfig {
  let base = GenValidConfig::binaryen_oracle_coverage_forced_default()
  GenValidConfig::{
    ..base,
    max_type_defs: 1,
    max_imports: 1,
    max_defined_funcs: 3,
    max_tables: 1,
    max_mems: 0,
    max_globals: 1,
    max_tags: 0,
    max_elems: 1,
    max_datas: 0,
    max_params: 1,
    max_results: 1,
    max_locals: 1,
    max_body_statements: 497,
    max_body_depth: 1,
    features: GenValidFeatureToggles::{
      ..base.features,
      allow_imports: true,
      allow_tables: true,
      allow_globals: true,
      allow_elems: true,
      allow_ref_types: true,
      allow_calls: true,
      allow_call_indirect: true,
      allow_tail_calls: true,
    },
  }
}

///|
fn gen_valid_campaign_call_topology_module(ctx : GenValidContext) -> Module {
  let seed = if ctx.use_named_streams {
    ctx.root_seed
  } else {
    ctx.rnd.next_uint64()
  }
  let variant = (seed % 12UL).to_int()
  let topology = (seed / 12UL % 4UL).to_int()
  let reversed_table = seed / 48UL % 2UL != 0UL
  let type_idx = TypeIdx::new(0U)
  let typed_ref = RefType::new(true, HeapType::new(type_idx))
  let arg = Instruction::local_get(LocalIdx::new(0U))
  let first_body = if topology == 1 || topology == 3 {
    [arg, Instruction::call(FuncIdx::new(0U))]
  } else {
    [
      arg,
      Instruction::i32_const(I32((seed >> 8).to_int())),
      Instruction::i32_xor(),
    ]
  }
  let second_body = match topology {
    0 | 1 =>
      [
        arg,
        Instruction::i32_const(I32((seed >> 16).to_int())),
        Instruction::i32_add(),
      ]
    2 => [arg, Instruction::call(FuncIdx::new(1U))]
    _ =>
      [
        arg,
        Instruction::call(FuncIdx::new(0U)),
        arg,
        Instruction::call(FuncIdx::new(1U)),
        Instruction::i32_add(),
      ]
  }
  let body = match variant {
    0 => [arg, Instruction::call(FuncIdx::new(0U))]
    1 => [arg, Instruction::call(FuncIdx::new(1U))]
    2 => [arg, Instruction::call(FuncIdx::new(2U))]
    3 => [arg, Instruction::return_call(FuncIdx::new(0U))]
    4 => [arg, Instruction::return_call(FuncIdx::new(2U))]
    5 =>
      [
        arg,
        Instruction::i32_const(I32(0)),
        Instruction::call_indirect(type_idx, TableIdx::new(0U)),
      ]
    6 =>
      [
        arg,
        Instruction::i32_const(I32(2)),
        Instruction::call_indirect(type_idx, TableIdx::new(0U)),
      ]
    7 =>
      [
        arg,
        Instruction::i32_const(I32(1)),
        Instruction::return_call_indirect(type_idx, TableIdx::new(0U)),
      ]
    8 =>
      [
        arg,
        Instruction::ref_func(FuncIdx::new(1U)),
        Instruction::call_ref(type_idx),
      ]
    9 =>
      [
        arg,
        Instruction::ref_func(FuncIdx::new(2U)),
        Instruction::local_set(LocalIdx::new(1U)),
        Instruction::local_get(LocalIdx::new(1U)),
        Instruction::call_ref(type_idx),
      ]
    10 =>
      [
        arg,
        Instruction::i32_const(I32(2)),
        Instruction::table_get(TableIdx::new(0U)),
        Instruction::return_call_ref(type_idx),
      ]
    _ =>
      [
        arg,
        Instruction::global_get(GlobalIdx::new(0U)),
        Instruction::call_ref(type_idx),
      ]
  }
  let table_funcs = if reversed_table {
    [FuncIdx::new(2U), FuncIdx::new(0U), FuncIdx::new(1U)]
  } else {
    [FuncIdx::new(0U), FuncIdx::new(1U), FuncIdx::new(2U)]
  }
  let table_entries : Array[Expr] = []
  for idx in table_funcs {
    table_entries.push(Expr::new([Instruction::ref_func(idx)]))
  }
  Module::new()
  .with_type_sec(
    TypeSec::new([
      RecType::new(
        SubType::comp_type(CompType::func([ValType::i32()], [ValType::i32()])),
      ),
    ]),
  )
  .with_import_sec(
    ImportSec::new([
      Import::new(
        Name::from_string("campaign"),
        Name::from_string("host"),
        ExternType::func(type_idx),
      ),
    ]),
  )
  .with_func_sec(FuncSec::new([type_idx, type_idx, type_idx]))
  .with_table_sec(
    TableSec::new([
      Table::new(TableType::new(typed_ref, Limits::i32(3U, Some(3U))), None),
    ]),
  )
  .with_global_sec(
    GlobalSec::new([
      Global::new(
        GlobalType::new(ValType::ref_type(typed_ref), false),
        Expr::new([Instruction::ref_func(FuncIdx::new(0U))]),
      ),
    ]),
  )
  .with_export_sec(
    ExportSec::new([
      Export::new(Name::from_string("run"), ExternIdx::func(FuncIdx::new(3U))),
    ]),
  )
  .with_elem_sec(
    ElemSec::new([
      Elem::new(
        ElemMode::active(
          TableIdx::new(0U),
          Expr::new([Instruction::i32_const(I32(0))]),
        ),
        ElemKind::typed_exprs(typed_ref, table_entries),
      ),
    ]),
  )
  .with_code_sec(
    CodeSec::new([
      Func::new(Locals::empty(), Expr::new(first_body)),
      Func::new(Locals::empty(), Expr::new(second_body)),
      Func::new(
        Locals::from_types([ValType::ref_type(typed_ref)]),
        Expr::new(body),
      ),
    ]),
  )
}