Tutorial: Embed in a C++ App

Link the BlazeRules core into a C++ application, load rules, evaluate an Arrow batch, and read decisions.

Goal: embed the BlazeRules engine directly in a C++ service so rule evaluation runs in-process with no Python on the hot path.

📘

See also

This tutorial is task-focused. For the full C++ surface (types, config enums, result accessors), see the C++ API reference.

Prerequisites

  • A C++20 toolchain and the BlazeRules build (blazerules_core) — see Installation.
  • The headers under include/blazerules/.

Step 1 — Link the core library

Link your target against the core library built by the project.

# CMakeLists.txt (consumer project)
target_link_libraries(my_service PRIVATE blazerules_core)

When consuming an installed package, the exported target is blazerules::blazerules_core. In-tree builds use blazerules_core.

Step 2 — Construct the engine and load rules

#include <blazerules/engine.h>

using namespace blazerules;

EngineConfig config;
config.output_detail = EngineConfig::OUTPUT_DECISIONS;  // C++ enum form; default is OUTPUT_BITMASKS

RuleEngine engine(config);
auto report = engine.load_rules("rules.yaml");  // returns a ConflictReport
📘

C++ vs Python config enums

The C++ EngineConfig enums are nested and unscoped — e.g. EngineConfig::OUTPUT_DECISIONS, EngineConfig::SKIP_AND_COUNT, EngineConfig::NULL_ON_TYPE_ERROR — and the default output_detail is OUTPUT_BITMASKS. The Python module exposes the friendlier OutputDetail.DECISIONS form.

Step 3 — Evaluate a batch

evaluate_batch accepts an Arrow RecordBatch; evaluate_ndjson accepts NDJSON bytes.

// arrow::RecordBatch batch = ...;
BatchResult result = engine.evaluate_batch(batch);

Step 4 — Read decisions

for (int i = 0; i < result.n_records; ++i) {
    const std::string& decision = result.decisions[i];
    double score = result.scores[i];
    const std::string& winning = result.winning_rule_ids[i];
    // route row i using decision / score / winning
}

const auto& approve_rows = result.grouped_decision_indices["APPROVE"];
auto timing = result.timing_ms();

Validation

  • load_rules succeeds (no thrown activation error) and the returned ConflictReport is clean.
  • The result's record count matches the input batch length.
  • Build in Release — Debug builds are dramatically slower (see Performance Model).

Where to go next