Packaging and Language Wrappers

Copperlace is implemented in Rust and exposed through native and language wrapper packages.

For the release operator checklist, see Copperlace release process.

Build Workflows

Use the root Makefile for normal development workflows:

make check
make package
make clean

make check runs Rust formatting checks plus Rust, Python, and Java tests. make package builds distributable CLI/native, Python, JS/TS, and Java artifacts for the current platform. make clean removes generated Rust, Python, JS/TS, and Java build output.

Release Automation

GitHub Actions builds and smoke-tests packages for pull requests and pushes to main. Version tags matching v* build the same package set, generate SHA256SUMS, and publish assets to the GitHub Release for that tag.

The first-class native release targets are:

  • linux-x86_64

  • linux-aarch64

  • macos-x86_64

  • macos-aarch64

  • windows-x86_64

Windows aarch64 is not part of the first release matrix. Other platforms may still work from source when Rust, Python, Java, or Node tooling is available, but packaged native artifacts are not promised for them.

Release assets include:

  • platform CLI archives containing the copperlace binary and native library;

  • Python wheels with the platform native library bundled under copperlace/native/, plus a source distribution that can build the bundled Rust core from source;

  • Java API, all-platform, and platform native JARs;

  • a JS/WASM package tarball generated from wasm-pack --target bundler;

  • SHA256SUMS for uploaded release assets.

Use make release-check locally to verify Cargo, Python, and Maven versions match before creating a release tag. Release tags should use the package version prefixed with v, such as v0.1.1.

Rust Artifacts

The Rust package in rust-core/ builds:

  • an rlib Rust library;

  • a cdylib native dynamic library;

  • the copperlace CLI binary.

  • a WebAssembly package when built with wasm-pack.

make cli-archive builds the current-platform CLI release archive under target/release-artifacts/.

The CLI supports:

copperlace render --config <path>
copperlace render -c <path> -r <name> --count <n> --set name=Mia
copperlace render -c <path> -r <object-rule> --compact-json

CLI rendering uses the builtin processor registry. If --rule is omitted, the CLI renders origin. --count renders multiple outputs from one loaded config. --set key=value provides initial context values for each render and may be repeated; duplicate keys use the last value.

The CLI infers output mode from the selected rule shape. String-valued and list-valued rules render as text. Object-valued rules render as structured JSON, formatted with tabs by default. Use --compact-json for compact JSON; with --count --compact-json, the CLI writes one compact JSON value per line.

C ABI

The native dynamic library exposes an opaque ruleset handle API:

  • copperlace_ruleset_from_file

  • copperlace_ruleset_from_file_with_processors

  • copperlace_ruleset_from_string

  • copperlace_ruleset_from_string_with_processors

  • copperlace_ruleset_render

  • copperlace_ruleset_render_with_context

  • copperlace_ruleset_render_structured_json

  • copperlace_ruleset_render_structured_json_with_context

  • copperlace_processor_result_set_output

  • copperlace_processor_result_set_error

  • copperlace_ruleset_free

  • copperlace_string_free

Returned strings are allocated by Copperlace and must be released with copperlace_string_free. Ruleset handles must be released with copperlace_ruleset_free. Custom processor callbacks must remain valid until the ruleset handle is freed.

Python Wrapper

The Python package in python/ uses ctypes over the C ABI. Public entry points are:

  • Copperlace.from_string(config, processors=None)

  • Copperlace.from_file(path, processors=None)

  • Copperlace.render(rule, context=None)

  • Copperlace.render_inferred(rule, context=None)

  • Copperlace.render_structured(rule, context=None)

  • RuleSet.from_string(config, processors=None)

  • RuleSet.from_file(path, processors=None)

  • RuleSet.render(rule, context=None)

  • RuleSet.render_inferred(rule, context=None)

  • RuleSet.render_structured(rule, context=None)

  • render_str(config, rule, context=None, processors=None)

  • render_file(path, rule, context=None, processors=None)

  • render_str_inferred(config, rule, context=None, processors=None)

  • render_file_inferred(path, rule, context=None, processors=None)

  • render_str_structured(config, rule, context=None, processors=None)

  • render_file_structured(path, rule, context=None, processors=None)

Copperlace is the recommended load-once API for repeated renders. Copperlace and RuleSet are context managers and release the native handle when closed. Wrapper failures are raised as CopperlaceError.

The wheel build compiles rust-core and bundles the platform native library under copperlace/native/. Linux wheels are repaired with auditwheel before publication so they use PyPI-compatible platform tags. The source distribution includes the Rust sources needed to build the native library from source.

PyPI releases publish:

  • platform wheels for Linux x86_64/aarch64, macOS x86_64/aarch64, and Windows x86_64;

  • one source distribution;

  • the same package version as Cargo, Java, and GitHub Release artifacts.

Python rendering uses the builtin processor registry plus any custom processor callbacks provided at construction time.

Python structured rendering is intentionally string-based. The wrapper keeps the Rust-to-Python boundary as rendering to text or structured JSON text instead of exposing a second structured value model. Inferred rendering also returns strings: normal text for string-valued and list-valued rules, or formatted JSON text for object-valued rules.

JS/TS WebAssembly Package

The JS/TS package in js/ is generated by wasm-pack from rust-core/. Public entry points are:

  • new Copperlace(config)

  • Copperlace.withProcessors(config, processors)

  • Copperlace.render(rule)

  • Copperlace.renderWithContext(rule, context)

  • renderString(config, rule)

  • renderStringWithContext(config, rule, context)

  • renderStringWithProcessors(config, rule, processors)

  • renderStringWithProcessorsAndContext(config, rule, processors, context)

Copperlace is the recommended load-once API for repeated renders in browser apps. Browser callers should load rule text themselves, usually with fetch, and pass the config string into Copperlace; file-path APIs are not exported to WebAssembly.

Build the bundler-oriented package with:

make js-package

Build a direct browser ES module package with:

make js-web

Both commands write generated output to js/pkg/, which is a build artifact. JS/TS rendering uses the builtin processor registry plus any custom processor functions provided at construction time.

Java Wrapper

The Java module in java/ uses Java FFM over the C ABI. The simplest Maven Central dependency is dev.mahe.copperlace:copperlace, which depends on the Java API plus all first-class supported native platform artifacts.

<dependency>
  <groupId>dev.mahe.copperlace</groupId>
  <artifactId>copperlace</artifactId>
  <version>0.1.1</version>
</dependency>

Gradle Kotlin DSL:

implementation("dev.mahe.copperlace:copperlace:0.1.1")

Applications that only want one runtime platform can depend on one platform artifact instead. Choose the runtime platform, not necessarily the build platform:

  • dev.mahe.copperlace:copperlace-linux-x86_64

  • dev.mahe.copperlace:copperlace-linux-aarch64

  • dev.mahe.copperlace:copperlace-macos-x86_64

  • dev.mahe.copperlace:copperlace-macos-aarch64

  • dev.mahe.copperlace:copperlace-windows-x86_64

Each platform artifact depends on dev.mahe.copperlace:copperlace-api transitively. Advanced users can depend on copperlace-api directly when they provide the native library through COPPERLACE_LIBRARY_PATH or source-tree build output.

Public entry points are:

  • Copperlace.fromString(config)

  • Copperlace.fromStringWithProcessors(config, processors)

  • Copperlace.fromFile(path)

  • Copperlace.fromFileWithProcessors(path, processors)

  • Copperlace.render(rule)

  • Copperlace.render(rule, context)

  • Copperlace.renderInferred(rule)

  • Copperlace.renderInferred(rule, context)

  • Copperlace.renderStructuredJson(rule)

  • Copperlace.renderStructuredJson(rule, formatJson)

  • Copperlace.renderStructuredJson(rule, context)

  • Copperlace.renderStructuredJson(rule, context, formatJson)

  • Copperlace.renderString(config, rule)

  • Copperlace.renderString(config, rule, context)

  • Copperlace.renderStringInferred(config, rule)

  • Copperlace.renderStringInferred(config, rule, context)

  • Copperlace.renderStringStructuredJson(config, rule)

  • Copperlace.renderStringStructuredJson(config, rule, formatJson)

  • Copperlace.renderStringStructuredJson(config, rule, context)

  • Copperlace.renderStringStructuredJson(config, rule, context, formatJson)

  • Copperlace.renderStringWithProcessors(config, rule, processors)

  • Copperlace.renderStringWithProcessors(config, rule, context, processors)

  • Copperlace.renderFile(path, rule)

  • Copperlace.renderFile(path, rule, context)

  • Copperlace.renderFileInferred(path, rule)

  • Copperlace.renderFileInferred(path, rule, context)

  • Copperlace.renderFileStructuredJson(path, rule)

  • Copperlace.renderFileStructuredJson(path, rule, formatJson)

  • Copperlace.renderFileStructuredJson(path, rule, context)

  • Copperlace.renderFileStructuredJson(path, rule, context, formatJson)

  • Copperlace.renderFileWithProcessors(path, rule, processors)

  • Copperlace.renderFileWithProcessors(path, rule, context, processors)

  • RuleSet.fromString(config)

  • RuleSet.fromStringWithProcessors(config, processors)

  • RuleSet.fromFile(path)

  • RuleSet.fromFileWithProcessors(path, processors)

  • RuleSet.render(rule)

  • RuleSet.render(rule, context)

  • RuleSet.renderInferred(rule)

  • RuleSet.renderInferred(rule, context)

  • RuleSet.renderStructuredJson(rule)

  • RuleSet.renderStructuredJson(rule, formatJson)

  • RuleSet.renderStructuredJson(rule, context)

  • RuleSet.renderStructuredJson(rule, context, formatJson)

Copperlace is the recommended load-once API for repeated renders. Copperlace and RuleSet implement AutoCloseable; callers should use try-with-resources or call close.

The Java API JAR contains only Java classes. Native binaries are packaged in platform artifacts for linux-x86_64, linux-aarch64, macos-x86_64, macos-aarch64, and windows-x86_64.

Plain Maven builds include the current-system native Java package by default when the staged native library exists under java/native-artifacts/<classifier>/. Maven does not compile the native library; use make java-package to build Rust, stage the current native library, and package the Java API plus current-platform native JAR. To build only the Java API, run Maven with -pl api.

At runtime, the Java wrapper loads the native library in this order:

  1. COPPERLACE_LIBRARY_PATH

  2. packaged classifier resource

  3. local Rust build output for source-tree development

Java rendering uses the builtin processor registry plus any custom processor callbacks provided at construction time.

Java structured rendering is intentionally string-based. The Java wrapper keeps the Rust-to-Java boundary as rendering to text or structured JSON text instead of exposing a second structured value model. No-argument structured JSON overloads return formatted JSON using tabs for indentation. The formatJson parameter controls serialization: false returns compact JSON and true returns formatted JSON. renderInferred also returns strings: normal text for string-valued and list-valued rules, or formatted JSON text for object-valued rules.