This could help us refactor the WASM shim and might make things easier for other clients. What do you thing, @zzcgumn? Here's what Cursor has to say:
The gap is explicit in specs/dds-public-api.md: the pure-C shim (dds_c_*) has binary-only entry points, while legacy dll.h has full *PBN twins and the modern C++ layer only has dds_calc_dd_table_pbn.
Current layers
| Layer |
PBN today |
Legacy dll.h |
Full pairing (SolveBoardPBN, CalcDDtablePBN, CalcParPBN, …) |
Modern dds_api.hpp |
Only dds_calc_dd_table_pbn |
C shim dds_c_api.h |
None — binary Deal / DdTableDeal only |
PBN structs already live in dll.h (DealPBN, DdTableDealPBN, …) and conversion is convert_from_pbn in PBN.h. The DD-table path already converts then delegates:
auto calc_dd_table_pbn(
SolverContext& ctx,
const DdTableDealPBN& table_deal_pbn,
DdTableResults* table_results) -> int
{
DdTableDeal table_deal;
if (convert_from_pbn(table_deal_pbn.cards, table_deal.cards) != RETURN_NO_FAULT)
return RETURN_PBN_FAULT;
return calc_dd_table(ctx, table_deal, table_results);
}
What a shim twin would look like
Same pattern as today’s binary exports: pointer-only, null-check, catch-all, forward to layer 2.
Header (dds_c_api.h):
DLLEXPORT int dds_c_calc_dd_table_pbn(DDS_C_SOLVER_CTX ctx,
const struct DdTableDealPBN* deal,
struct DdTableResults* results);
Impl (dds_c_api.cpp) — mirrors dds_c_calc_dd_table:
DLLEXPORT int dds_c_calc_dd_table_pbn(DDS_C_SOLVER_CTX ctx,
const struct DdTableDealPBN* deal,
struct DdTableResults* results)
{
if (ctx == nullptr || deal == nullptr || results == nullptr)
return RETURN_UNKNOWN_FAULT;
try {
return dds_calc_dd_table_pbn(static_cast<SolverContext*>(ctx),
*deal, results);
} catch (...) {
return RETURN_UNKNOWN_FAULT;
}
}
That’s the smallest useful addition: one export, already backed by dds_calc_dd_table_pbn.
Fuller pairing (if you want solve/par too)
Those need modern API first (shim only forwards):
// dds_api.hpp
int dds_solve_board_pbn(DDS_SOLVER_CTX ctx, const DealPBN& dl, ...);
int dds_calc_par_pbn(DDS_SOLVER_CTX ctx, const DdTableDealPBN& deal, ...);
// dds_c_api.h
int dds_c_solve_board_pbn(DDS_C_SOLVER_CTX ctx, const struct DealPBN* dl, ...);
int dds_c_calc_par_pbn(DDS_C_SOLVER_CTX ctx, const struct DdTableDealPBN* deal, ...);
Implement like legacy SolveBoardPBN: convert_from_pbn → copy trump/first/trick → call binary dds_*. Bad PBN → RETURN_PBN_FAULT.
Plumbing after the symbols
- Regenerate export lists (
jni/gen_export_lists.py → version_script.lds / exported_symbols.lds); //jni/tests:export_set_test must stay green.
- Java FFM: add
DEAL_PBN / DD_TABLE_DEAL_PBN layouts and downcalls in jni/java/org/dds/ffm/Dds.java.
- Update the shim docs/spec lines that say “no
*PBN twins”.
Design choice
- Minimal: only
dds_c_calc_dd_table_pbn — matches what’s already on the modern layer; enough for the web/Java “hand me a PBN string” case.
- Symmetric: add solve/par PBN on both
dds_* and dds_c_* so the shim mirrors the binary trio.
- Don’t grow
dll.h — new work goes on the context API + shim.
I wouldn’t expose a raw convert_from_pbn on the shim unless bindings need it; keep conversion inside the *_pbn entry points.
This could help us refactor the WASM shim and might make things easier for other clients. What do you thing, @zzcgumn? Here's what Cursor has to say:
The gap is explicit in
specs/dds-public-api.md: the pure-C shim (dds_c_*) has binary-only entry points, while legacydll.hhas full*PBNtwins and the modern C++ layer only hasdds_calc_dd_table_pbn.Current layers
dll.hSolveBoardPBN,CalcDDtablePBN,CalcParPBN, …)dds_api.hppdds_calc_dd_table_pbndds_c_api.hDeal/DdTableDealonlyPBN structs already live in
dll.h(DealPBN,DdTableDealPBN, …) and conversion isconvert_from_pbninPBN.h. The DD-table path already converts then delegates:What a shim twin would look like
Same pattern as today’s binary exports: pointer-only, null-check, catch-all, forward to layer 2.
Header (
dds_c_api.h):Impl (
dds_c_api.cpp) — mirrorsdds_c_calc_dd_table:That’s the smallest useful addition: one export, already backed by
dds_calc_dd_table_pbn.Fuller pairing (if you want solve/par too)
Those need modern API first (shim only forwards):
Implement like legacy
SolveBoardPBN:convert_from_pbn→ copy trump/first/trick → call binarydds_*. Bad PBN →RETURN_PBN_FAULT.Plumbing after the symbols
jni/gen_export_lists.py→version_script.lds/exported_symbols.lds);//jni/tests:export_set_testmust stay green.DEAL_PBN/DD_TABLE_DEAL_PBNlayouts and downcalls injni/java/org/dds/ffm/Dds.java.*PBNtwins”.Design choice
dds_c_calc_dd_table_pbn— matches what’s already on the modern layer; enough for the web/Java “hand me a PBN string” case.dds_*anddds_c_*so the shim mirrors the binary trio.dll.h— new work goes on the context API + shim.I wouldn’t expose a raw
convert_from_pbnon the shim unless bindings need it; keep conversion inside the*_pbnentry points.