Files
wickra/CONTRIBUTING.md
T
kingchenc 167f7b3ffe Add the Java binding over the C ABI hub (Panama/FFM) (#233)
Adds a Java binding (`bindings/java`) over the C ABI hub — the fourth language stecker after C#, Go and R, reaching the hub through the Java Foreign Function & Memory API (Panama, `java.lang.foreign`, final in Java 22) rather than JNI or jextract.

## What's here
- **`bindings/java`** — a Maven module (`org.wickra:wickra`) exposing all 514 indicators as idiomatic `AutoCloseable` classes. The downcall handles (`internal/NativeMethods.java`), the per-indicator wrappers and the output records are generated from `bindings/c/include/wickra.h` (same eight-archetype taxonomy as the C#/Go/R generators: scalar/batch, multi-output, bars, profile, values-profile, array-input). The opaque handle is a `MemorySegment` freed by a registered `java.lang.ref.Cleaner` action; multi-output returns a `record` (`null` at warmup), bars a `record[]`, profiles a record with a trailing `double[]`. The hand-written `WickraNative` resolves the native library (a bundled per-platform copy, or a `target/release` fallback for local development) and validates it against a sentinel symbol. repr(C) struct offsets are computed in the generator so the FFM reads land on the exact bytes.
- **`examples/java`** — the full example suite mirroring C/C#/Go/R: streaming, backtest, multi_timeframe, parallel_assets (parallel streams), three strategies, and `FetchBtcusdt`/`LiveBinance`.
- **CI** — a `java` job builds the C ABI library, sets up JDK 22 (Temurin, with a CDN-flake retry), runs the archetype test suite and the seven offline examples on Linux, macOS and Windows.
- **Release** — a gated `java-publish` job (skipped until the `JAVA_PUBLISH_ENABLED` repository variable is set) stages the native libraries from the `wickra-c-<triple>.tar.gz` assets into the binding's resources and deploys to Maven Central with GPG signing. Independent of the GitHub-release job, like the NuGet job.
- **Docs** — Java added to the README languages table, project layout, building/testing and comparison table, CONTRIBUTING, ARCHITECTURE, the examples index, the issue/PR templates, the About-description template, and the other binding READMEs.

## Requirements
Java 22+ (the FFM API is final since Java 22). The binding requires `--enable-native-access=ALL-UNNAMED` at runtime; the test and example runners pass it automatically.

No Rust crate or `Cargo.toml` change — the Java binding is standalone and additive. The generated `*.java` are committed (like the node `index.js`/`index.d.ts`); the generator stays private.
2026-06-09 20:30:29 +02:00

8.2 KiB

Contributing to Wickra

Thanks for your interest in improving Wickra. This document explains how to build the project, the standards a change must meet, and how to get it merged.

License of contributions

Wickra is dual-licensed under the MIT and Apache-2.0 licenses; users may choose either. Unless you explicitly state otherwise, any contribution you intentionally submit for inclusion in the work, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Project layout

Path Contents
crates/wickra-core The indicator engine — every indicator lives here.
crates/wickra Thin umbrella crate re-exporting wickra-core.
crates/wickra-data CSV reader, tick aggregator, resampler, Binance feed.
bindings/python PyO3 bindings (wickra on PyPI).
bindings/node napi-rs bindings (wickra on npm).
bindings/wasm wasm-bindgen bindings (wickra-wasm on npm).
bindings/c C ABI — cdylib + staticlib + generated include/wickra.h. The hub for C / C++ and any C-capable language.
bindings/csharp .NET binding over the C ABI (Wickra on NuGet) — [LibraryImport] P/Invoke generated from wickra.h.
bindings/go Go binding over the C ABI via cgo (module tag bindings/go/vX.Y.Z) — wrappers generated from wickra.h.
bindings/r R binding over the C ABI via .Call (R package) — C glue + R wrappers generated from wickra.h.
bindings/java Java binding over the C ABI via the FFM API (Panama, Maven Central) — wrappers generated from wickra.h.
examples/ Runnable examples.
docs/ Pointer to the documentation site (docs.wickra.org); the docs live in the wickra-lib/wickra-docs repo.

Building and testing

Rust

cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo test -p wickra-data --features live-binance

The minimum supported Rust version is 1.86 for the workspace crates and 1.88 for bindings/node; the msrv CI job enforces both. These floors are not chosen freely — they are the lowest versions our dependencies allow (criterion 0.8.2, the bench dev-dependency, requires 1.86; napi-build 2.3.2 requires 1.88). We keep the MSRV at that dependency-forced floor on purpose so the library builds for the widest possible audience; please don't raise it without a dependency that actually requires it.

Python

cd bindings/python
python -m maturin build --release --out dist
python -m pip install --force-reinstall --no-deps dist/wickra-*.whl
python -m pytest -q

Node

cd bindings/node
npm install
npx napi build --platform --release
node --test __tests__/

WASM

wasm-pack build bindings/wasm --target web --release --features panic-hook
wasm-pack test --node bindings/wasm

Lockfile policy

Component Lockfile Tracked? Why
Workspace (Rust) Cargo.lock yes The workspace ships binaries (examples, fuzz harness) and CI builds, so the dependency graph is pinned for reproducible builds.
bindings/node package-lock.json yes Reproducible npm install for the native binding.
examples/node package-lock.json yes Same — the runnable Node examples link the binding via a file: dependency.
bindings/python n/a (no lockfile) The published package pins only numpy>=1.22 at runtime; its native code is pinned through the workspace Cargo.lock. The CI/bench dev tooling it installs is hash-locked separately — see the .github/requirements row.
.github/requirements *.txt (hash-pinned) yes CI/bench Python tooling, locked with uv pip compile --generate-hashes (OpenSSF Scorecard PinnedDependencies). ci-dev is split per Python version — ci-dev-py39.txt and ci-dev-py3.txt — because numpy ships no single release with wheels for both cp39 and cp313; bench.txt covers the single-version bench job.
fuzz fuzz/Cargo.lock no (ignored) fuzz/ is a detached crate; cargo-fuzz init generates fuzz/.gitignore which ignores its Cargo.lock. The fuzz smoke job resolves dependencies fresh, so the lock is not needed for reproducibility here.
site (marketing) package-lock.json no (ghost-ignored) The VitePress site is a local-only project excluded via .git/info/exclude; its lockfile stays local.

When adding a new committed Node package, commit its package-lock.json too and remove any matching ignore rule. Do not add a top-level package-lock.json — the repository root is not an npm package.

To refresh every committed lockfile in the workspace — Cargo.lock, fuzz/Cargo.lock, the Node binding lock, and the hash-pinned Python requirements — run ./scripts/update-lockfiles.sh. It uses uv for the Python locks (and bootstraps it on Linux/macOS if absent) so each target Python version's hashed transitive closure can be regenerated without that interpreter installed. Dependabot also keeps the .github/requirements pins current.

Standards for a change

  • Formatting & lints. cargo fmt must leave the tree unchanged and cargo clippy ... -D warnings must be clean. CI gates both.
  • Tests. New behaviour needs tests; bug fixes need a regression test.
  • Indicator correctness. A new or changed indicator must have a reference-value test against a known-good source (TA-Lib, pandas-ta, or a hand-computed value) and a reset test.
  • Streaming parity. An indicator's batch output must equal the sequence of update calls.
  • Bindings. A change to a public indicator API must be mirrored across the Python, Node, and WASM bindings, including their type stubs / .d.ts. The C ABI (bindings/c) is generated from the core, so regenerate it from the core and commit src/lib.rs + include/wickra.h. The C# binding (bindings/csharp) is generated from wickra.h, so regenerate and commit its Generated/*.g.cs too. The Go binding (bindings/go) is likewise generated from wickra.h, so regenerate and commit indicators_gen.go (gofmt-clean). The R binding (bindings/r) is generated from wickra.h too, so regenerate and commit src/wickra.c + R/indicators.R. The Java binding (bindings/java) is generated from wickra.h as well, so regenerate and commit its src/main/java/org/wickra/*.java.
  • Docs. Update the relevant page on the documentation site and the README.md when behaviour or the public API changes. The docs live in a separate git repository: https://github.com/wickra-lib/wickra-docs.
  • Changelog. Add an entry under ## [Unreleased] in CHANGELOG.md.

Commit and pull-request workflow

  1. Branch off main.
  2. Keep commits focused — one logical change per commit, with an imperative subject line and a body explaining why.
  3. Open a pull request against main and fill in the template.
  4. CI must be green before review.

Reporting bugs and proposing features

Use the issue templates under .github/ISSUE_TEMPLATE. For security-sensitive reports, follow SECURITY.md instead of opening a public issue.

Developer Certificate of Origin (DCO)

All contributions to Wickra are made under the Developer Certificate of Origin (DCO) 1.1. By signing off on your commits you certify that you wrote the patch, or otherwise have the right to submit it under the project's MIT OR Apache-2.0 license.

Sign off every commit by adding a Signed-off-by trailer with your real name and email — Git adds it automatically with the -s flag:

git commit -s -m "your message"

This produces a trailer of the form:

Signed-off-by: Your Name <you@example.com>

The name and email must match the commit author. Commits without a valid sign-off line cannot be merged. To sign off a commit you already made, amend it with git commit -s --amend, or sign off a range with an interactive rebase.

Governance

Wickra's decision-making and maintainership are described in GOVERNANCE.md; the current maintainers are listed in MAINTAINERS.md.