// ===== jsonld 性能基线 harness(常备;役P1 立账,2026-10-09)=====
// 规则:native 后端(preferred_target);计时 = @async.now()(ms 墙钟);
//       每场景 warmup 1 + k=5 计时取**中位数**(读数 = perf-baseline.txt)。
// 语料:进程内确定性生成(零仓库膨胀;形状注记同笔入 perf-baseline.txt)。
// 自报读数行(与套件的自报同族,可直接 grep):
//       `[bench] scenario=<名> n=<规模> median=ms k=5 runs=[...]`
// 判据线:任一场景中位数回归 >10%(超噪声带)即红——perf-baseline.txt 头。
// 前置检查:计时前每场景先跑一次**结构断言**(Ok + 规模哨兵)——计错误结果
//       即垃圾读数(⑤勘察工具自身可能被污染;J2 fixture 教训)。

///|
fn main {
  bench_all()
}

///|
fn bench_all() -> Unit {
  scenario_parse_wide()
  scenario_scoped_heavy()
  scenario_expand_wide()
  scenario_expand_deep()
  scenario_expand_nest()
  scenario_compact_wide()
  scenario_flatten_wide()
  scenario_to_rdf_wide()
  scenario_from_rdf_wide()
  scenario_canon_chain()
}

///|
/// 计时轮:warmup 1 + k 次取中位数。返回(中位数 ms,各次读数展示串)。
fn time_median(k : Int, f : () -> Unit) -> (Int, String) {
  f() // warmup:页缓存 / 分配器稳定
  let runs : Array[Int] = []
  for _ in 0.. 0 {
      disp.write_string(",")
    }
    disp.write_string(runs[i].to_string())
  }
  (runs[runs.length() / 2], disp.to_string())
}

///|
fn report(scenario : String, n : Int, median : Int, runs : String) -> Unit {
  println(
    "[bench] scenario=\{scenario} n=\{n} median=\{median}ms k=5 runs=\{runs}",
  )
}

///|
fn fail(scenario : String, why : String) -> Unit {
  println("[bench-fail] scenario=\{scenario} why=\{why}")
}

///|
/// 全场景共用 options(与 cmd/main make_options 同款缺省;base None)。
fn bench_options() -> @jsonld.JsonLdOptions {
  {
    base: None,
    expand_context: None,
    processing_mode: @jsonld.ProcessingMode::JsonLd11,
    load_context: None,
    rdf_direction: None,
    produce_generalized_rdf: false,
    compact_arrays: true,
    compact_to_relative: true,
    frame_expansion: false,
    omit_graph: false,
    use_native_types: false,
    use_rdf_type: false,
  }
}

// ===== 语料生成(确定性;形状注记见 perf-baseline.txt)=====

///|
/// wide:单节点 N 属性(http://ex/p = "v")。
/// expand / compact / toRdf / flatten / parse 五场景共用形状。
fn gen_wide_doc(n : Int) -> String {
  let sb = StringBuilder()
  sb.write_string("{\"@id\":\"http://ex/root\"")
  for i in 0.. → http://ex/p)。
fn gen_wide_ctx(n : Int) -> String {
  let sb = StringBuilder()
  sb.write_string("{")
  for i in 0.. 0 {
      sb.write_string(",")
    }
    sb.write_string("\"p")
    sb.write_string(i.to_string())
    sb.write_string("\":\"http://ex/p")
    sb.write_string(i.to_string())
    sb.write_string("\"")
  }
  sb.write_string("}")
  sb.to_string()
}

///|
/// deep:链式嵌套 D 层(每层 http://ex/p + http://ex/n 下钻;底层哨兵 http://ex/bottom)。
fn gen_deep_doc(depth : Int) -> String {
  let sb = StringBuilder()
  for _ in 0.. String {
  let sb = StringBuilder()
  sb.write_string("{")
  for i in 0.. 0 {
      sb.write_string(",")
    }
    sb.write_string("\"n")
    sb.write_string(i.to_string())
    sb.write_string("\":\"@nest\"")
  }
  for i in 0.. String {
  let sb = StringBuilder()
  for i in 0.. 0 {
      sb.write_string(",")
    }
    sb.write_string("\"t")
    sb.write_string(i.to_string())
    sb.write_string("\":\"x")
    sb.write_string(i.to_string())
    sb.write_string("\"")
  }
  sb.to_string()
}

///|
/// fromRdf 语料:N 条独立三元组(s p v)。
fn gen_nquads_flat(n : Int) -> String {
  let sb = StringBuilder()
  for i in 0..  \"v")
    sb.write_string(i.to_string())
    sb.write_string("\" .\n")
  }
  sb.to_string()
}

///|
/// canon 语料:N 环 bnode 链(每环 2 条:值 + 下钻)——n-degree 哈希沿线展开。
fn gen_nquads_chain(n : Int) -> String {
  let sb = StringBuilder()
  for i in 0.. \"v")
    sb.write_string(i.to_string())
    sb.write_string("\" .\n_:b")
    sb.write_string(i.to_string())
    sb.write_string("  _:b")
    sb.write_string((i + 1).to_string())
    sb.write_string("\" .\n")
  }
  sb.to_string()
}

// ===== 场景 =====

///|
/// parse 分解列:wide 文档纯解析(parse_json)——算法面成本 = 总成本 − 解析。
fn scenario_parse_wide() -> Unit {
  let n = 20000
  let doc = gen_wide_doc(n)
  match @jsonld.parse_json(doc) {
    Ok(jv) =>
      if @jsonld.render_json(jv).length() < doc.length() / 2 {
        fail("parse_wide", "parsed value implausibly small")
        return
      }
    Err(_) => {
      fail("parse_wide", "parse err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() { let _ = @jsonld.parse_json(doc) })
  report("parse_wide", n, median, runs)
}

///|
fn scenario_expand_wide() -> Unit {
  let n = 20000
  let doc = gen_wide_doc(n)
  match @jsonld.expand_document(doc, bench_options()) {
    Ok(jv) => {
      let out = @jsonld.render_json(jv)
      if out.find("http://ex/p0") is None ||
        out.find("http://ex/p\{n - 1}") is None {
        fail("expand_wide", "sentinel props missing (truncated corpus?)")
        return
      }
    }
    Err(_) => {
      fail("expand_wide", "expand err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.expand_document(doc, bench_options())
  })
  report("expand_wide", n, median, runs)
}

///|
fn scenario_expand_deep() -> Unit {
  // depth=800:core @json.parse 默认最大嵌深 1024(J0 勘察),贴近上限取信号;
  // 递归/分派成本渐近段形态注记见 perf-baseline.txt。
  let depth = 800
  let doc = gen_deep_doc(depth)
  match @jsonld.expand_document(doc, bench_options()) {
    Ok(jv) =>
      if @jsonld.render_json(jv).find("http://ex/bottom") is None {
        fail("expand_deep", "bottom sentinel missing (depth truncated?)")
        return
      }
    Err(_) => {
      fail("expand_deep", "expand err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.expand_document(doc, bench_options())
  })
  report("expand_deep", depth, median, runs)
}

///|
fn scenario_expand_nest() -> Unit {
  let m = 2000
  let ctx = gen_nest_ctx(m)
  let doc = gen_nest_doc(m)
  let full = "{\"@context\":\{ctx},\{doc}}"
  match @jsonld.expand_document(full, bench_options()) {
    Ok(jv) => {
      // 展开语义:nest 属性上浮——产出**无** "@nest" 键,哨兵 = 首末属性 IRI 在场
      let out = @jsonld.render_json(jv)
      if out.find("\"@nest\"") is Some(_) {
        fail("expand_nest", "@nest keys survived expansion (semantics broken?)")
        return
      }
      if out.find("http://ex/t0") is None || out.find("http://ex/t1999") is None {
        fail("expand_nest", "sentinel props missing (truncated corpus?)")
        return
      }
    }
    Err(_) => {
      fail("expand_nest", "expand err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.expand_document(full, bench_options())
  })
  report("expand_nest", m, median, runs)
}

///|
fn scenario_compact_wide() -> Unit {
  let n = 20000
  let doc = gen_wide_doc(n)
  let ctx = gen_wide_ctx(n)
  match @jsonld.compact_document(doc, ctx, bench_options()) {
    Ok(jv) => {
      let out = @jsonld.render_json(jv)
      if out.find("\"p0\"") is None || out.find("\"p\{n - 1}\"") is None {
        fail("compact_wide", "sentinel terms missing (truncated corpus?)")
        return
      }
    }
    Err(_) => {
      fail("compact_wide", "compact err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.compact_document(doc, ctx, bench_options())
  })
  report("compact_wide", n, median, runs)
}

///|
fn scenario_flatten_wide() -> Unit {
  let n = 20000
  let doc = gen_wide_doc(n)
  match @jsonld.flatten_document(doc, bench_options()) {
    Ok(jv) => {
      let out = @jsonld.render_json(jv)
      if out.find("http://ex/root") is None {
        fail("flatten_wide", "root IRI missing")
        return
      }
    }
    Err(_) => {
      fail("flatten_wide", "flatten err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.flatten_document(doc, bench_options())
  })
  report("flatten_wide", n, median, runs)
}

///|
fn scenario_to_rdf_wide() -> Unit {
  let n = 20000
  let doc = gen_wide_doc(n)
  match @jsonld.to_rdf_document(doc, bench_options()) {
    Ok(quads) =>
      if quads.length() != n {
        fail("to_rdf_wide", "quad count \{quads.length()} != \{n}")
        return
      }
    Err(_) => {
      fail("to_rdf_wide", "toRdf err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.to_rdf_document(doc, bench_options())
  })
  report("to_rdf_wide", n, median, runs)
}

///|
fn scenario_from_rdf_wide() -> Unit {
  // n=4000:首轮实测 n=20000 中位数 25.4s(runs 13.7~37.8s,方差大)——
  // fromRdf 是**头号热点信号**(P3 勘察主发现);规模降到基线套件可承受量级,
  // 扩散律(线性 vs 二次)留探针批专测。
  let n = 4000
  let nq = gen_nquads_flat(n)
  match @jsonld.from_rdf_document(nq, bench_options()) {
    Ok(jv) => {
      let out = @jsonld.render_json(jv)
      if out.find("http://ex/s\{n - 1}") is None {
        fail("from_rdf_wide", "last subject missing (truncated corpus?)")
        return
      }
    }
    Err(_) => {
      fail(
        "from_rdf_wide", "fromRdf err (复现:moon run cmd/main 同输入)",
      )
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.from_rdf_document(nq, bench_options())
  })
  report("from_rdf_wide", n, median, runs)
}

///|
fn scenario_canon_chain() -> Unit {
  let n = 1500
  let nq = gen_nquads_chain(n)
  match
    @jsonld.rdfc10_canonicalize_with_hash(nq, @jsonld.C14nHashAlgorithm::Sha256) {
    Ok((canonical, _issued)) =>
      if canonical.length() < n * 20 {
        fail("canon_chain", "canonical output implausibly small")
        return
      }
    Err(_) => {
      fail("canon_chain", "canon err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.rdfc10_canonicalize_with_hash(
      nq,
      @jsonld.C14nHashAlgorithm::Sha256,
    )
  })
  report("canon_chain", n, median, runs)
}

///|
/// scoped_heavy(役P1 批7 转正——**COW 回归门**;批6 双判据的负载线校验):
/// J2 同形 = N 节点 × term-ful property-scoped 应用(父 context 200 terms;
/// 每节点 sc 触发 process_context :3564 克隆径)。守什么:context 克隆路径
/// 的份额与线性(批6 实测 158ms/2000×200 = 0.38µs/term,O(N×T))——谁动
/// context 复制/共享语义(含 COW),此场景先红。
fn scenario_scoped_heavy() -> Unit {
  let n_nodes = 2000
  let n_terms = 200
  let sb = StringBuilder()
  sb.write_string("{\"@context\":{")
  for i in 0.. 0 {
      sb.write_string(",")
    }
    sb.write_string("\"t")
    sb.write_string(i.to_string())
    sb.write_string("\":\"http://ex/t")
    sb.write_string(i.to_string())
    sb.write_string("\"")
  }
  // sc:td 带 @context(property-scoped;含 term 条目 ⇒ 克隆径)
  sb.write_string(
    ",\"sc\":{\"@id\":\"http://ex/sc\",\"@context\":{\"extra\":\"http://ex/extra\"}}",
  )
  sb.write_string("},\"@graph\":[")
  for i in 0.. 0 {
      sb.write_string(",")
    }
    sb.write_string("{\"@id\":\"http://ex/n")
    sb.write_string(i.to_string())
    sb.write_string("\",\"sc\":{\"extra\":\"v\"}}")
  }
  sb.write_string("]}")
  let doc = sb.to_string()
  match @jsonld.expand_document(doc, bench_options()) {
    Ok(jv) => {
      let out = @jsonld.render_json(jv)
      // 哨兵:scoped context 已应用(extra 展开在场)+ 全节点数保真
      if out.find("http://ex/extra") is None {
        fail("scoped_heavy", "scoped ctx not applied (clone path idle?)")
        return
      }
      if out.find("http://ex/n1999") is None {
        fail("scoped_heavy", "sentinel node missing (truncated corpus?)")
        return
      }
    }
    Err(_) => {
      fail("scoped_heavy", "expand err (复现:moon run cmd/main 同输入)")
      return
    }
  }
  let (median, runs) = time_median(5, fn() {
    let _ = @jsonld.expand_document(doc, bench_options())
  })
  report("scoped_heavy", n_nodes, median, runs)
}