ddss 0.1.0

Rusty API for ddss, a performance-oriented fork of the DDS double dummy solver for bridge
docs.rs failed to build ddss-0.1.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

ddss

Build Status Crates.io Docs.rs

Rusty API for ddss, a performance-oriented fork of the DDS double dummy solver for bridge. ddss is based on DDS 2.9.0 and keeps the 2.9 design — a single persistent internal thread pool with non-reentrant entry points. This crate wraps the raw ddss-sys FFI bindings behind a Solver guard that serializes access to that pool.

Example

use contract_bridge::{FullDeal, Seat, Strain};
use ddss::Solver;

# fn main() -> Result<(), Box<dyn core::error::Error>> {
let deal: FullDeal = "N:AKQJT98765432... .AKQJT98765432.. \
                      ..AKQJT98765432. ...AKQJT98765432".parse()?;
let solver = Solver::lock();
let tricks = solver.solve_deal(deal);
assert_eq!(u8::from(tricks[Strain::Spades].get(Seat::North)), 13);
# Ok(())
# }

Threading

Solver is a guard, not an owned context. ddss exposes a global thread pool that is initialized once (via SetMaxThreads(0)) on first lock acquisition. Hold a Solver once for a batch of related calls to avoid repeated locking. Batch entry points (solve_deals, solve_boards) parallelize internally across that pool — there is no need for caller-side rayon.

Because Solver wraps a parking_lot::MutexGuard<'static, ()>, it is !Send: the lock must be released on the same OS thread that acquired it. Spawn one thread per solving job and acquire the lock inside that thread.

Relationship to dds-bridge

dds-bridge wraps a different sys crate (dds-bridge-sys, DDS 3.x) with a per-context Solver design that fits DDS 3's reentrant API. This crate is the analogous wrapper for ddss; the two cannot link in the same binary because their underlying C libraries export overlapping symbols.