C Stable API

Solving

Prepare an opaque C session and solve independent request snapshots.

The solving concept explains the evaluation pipeline. Here, the C facade prepares one selected policy in an opaque maelys_datalog_session_t and returns one opaque result per successful solve. A session keeps the selected policy prepared for independent requests.

Types

Defined on this page

TypePurpose
maelys_datalog_session_tOpaque prepared policy and per-request working state.
maelys_datalog_session_config_tOptional requirements and memory configuration fixed at session creation.
maelys_datalog_result_tOne successful solve's answer; release before solving again on the same session.

Used from other pages

These types are defined on the linked pages; this page uses them in the roles below.

TypeUse on this pageDefined in
maelys_datalog_policy_tInput handle selecting the policy to prepare.Manifests
maelys_datalog_input_edb_tInput buffer containing the complete request.EDB
maelys_datalog_fact_tInput array element for an array-based solve.EDB
maelys_datalog_diagnostic_tOptional output argument receiving solve details.Errors

Functions

FunctionPurpose
maelys_datalog_session_create()Prepare one selected policy with defaults.
maelys_datalog_session_create_configured()Prepare it with explicit requirements.
maelys_datalog_session_solve_edb()Evaluate a complete opaque input buffer.
maelys_datalog_session_solve()Evaluate a borrowed fact array for one request.
maelys_datalog_session_fingerprint()Identify the selected policy authority.
maelys_datalog_session_execution_fingerprint()Identify that authority together with execution settings.
maelys_datalog_session_free()Release the session after its result.

Opaque lifecycle types

C · opaque
maelys_datalog_session_t
typedef struct maelys_datalog_session maelys_datalog_session_t;
Prepared policy and bounded solver workspace reused for independent requests. One live result may belong to it at a time.
C · opaque
maelys_datalog_session_config_t
typedef struct maelys_datalog_session_config maelys_datalog_session_config_t;
Optional requirements and memory choices applied when a session is created. Configuration is not a second policy.
C · opaque
maelys_datalog_result_t
typedef struct maelys_datalog_result maelys_datalog_result_t;
Answer to one successful solve. Query and explain it while live, then release it before reusing its session.

Create and select a session

A loaded handle may hold more than one policy. Use maelys_datalog_policy_count() to find its valid indices; an inline load has just index 0. Creating a session prepares one selected policy. Use the default call below unless you need the configured variant.

To prepare the selected policy:

C · function
Create a session
maelys_datalog_status_t
maelys_datalog_session_create(
const maelys_datalog_policy_t * policy,
size_t policy_index,
maelys_datalog_session_t ** out_session
);
Prepares one policy selected by its index for repeated requests. No input facts are supplied and no answer is computed yet.
Arguments
policyconst maelys_datalog_policy_t *
Loaded set containing the policy to prepare.
policy_indexsize_t
Zero-based index within that set.
out_sessionmaelys_datalog_session_t **
Receives a prepared session on success.
Return value
maelys_datalog_status_t

Returns OK with a new session, or an error without publishing a session.

CODE
maelys_datalog_session_t *session = NULL;
maelys_datalog_status_t status =
    maelys_datalog_session_create(policy, 0u, &session);

The session is fixed to its selected policy. To prepare a different policy in the same loaded set, create another session with its own index. A session owns the prepared state after creation, so its policy handle may then be freed.

Solve one complete request

Give the prepared session the entire fact snapshot for this request. A successful call returns a new result; the input is not appended to the prior request.

C · function
Solve a request from an input EDB
maelys_datalog_status_t
maelys_datalog_session_solve_edb(
maelys_datalog_session_t * session,
const maelys_datalog_input_edb_t * edb,
maelys_datalog_result_t ** out_result,
maelys_datalog_diagnostic_t * out_diagnostic
);
Evaluates the selected policy against all facts in an input EDB. Each call is a complete request snapshot, not an incremental update to the previous result.
Arguments
sessionmaelys_datalog_session_t *
Prepared session selecting one policy.
edbconst maelys_datalog_input_edb_t *
Complete input fact set for this request.
out_resultmaelys_datalog_result_t **
Receives a result on success; release it before solving again on this session.
out_diagnosticmaelys_datalog_diagnostic_t *
Optional structured solve diagnostic.
Return value
maelys_datalog_status_t

A successful result belongs to this session until it is freed.

CODE
maelys_datalog_result_t *result = NULL;
maelys_datalog_status_t status = maelys_datalog_session_solve_edb(
    session, edb, &result, &diagnostic);

When the caller already has a typed fact array, it may submit that complete snapshot without creating an input EDB:

C · function
Solve a borrowed fact array
maelys_datalog_status_t
maelys_datalog_session_solve(
maelys_datalog_session_t * session,
const maelys_datalog_fact_t * facts,
size_t fact_count,
maelys_datalog_result_t ** out_result,
maelys_datalog_diagnostic_t * out_diagnostic
);
Evaluates the selected policy against a fact array supplied by the application, without requiring an input EDB handle.
Arguments
sessionmaelys_datalog_session_t *
Prepared session selecting one policy.
factsconst maelys_datalog_fact_t *
Complete typed fact array borrowed for this call.
fact_countsize_t
Number of input facts.
out_resultmaelys_datalog_result_t **
Receives a result on success.
out_diagnosticmaelys_datalog_diagnostic_t *
Optional solve diagnostic.
Return value
maelys_datalog_status_t

Returns OK with a new result; failure publishes no result.

CODE
maelys_datalog_result_t *result = NULL;
maelys_datalog_status_t status = maelys_datalog_session_solve(
    session, facts, fact_count, &result, &diagnostic);

maelys_datalog_session_solve() borrows a fact array for one call; maelys_datalog_session_solve_edb() borrows a previously filled opaque input buffer for one call. Both return a maelys_datalog_result_t * on success and publish no result on failure. They do not append to a previous request. One result may be live per reference session: release it before another solve or before freeing the session. See runtime EDB for building input facts and querying for inspecting the result.

Example — document access

The one-policy inline handle selects documents.main at index 0. After the seven request facts have been added, the session evaluates the policy once:

CODE
maelys_datalog_session_t *session = NULL;
maelys_datalog_status_t status =
    maelys_datalog_session_create(policy, 0u, &session);
if (status != MAELYS_DATALOG_STATUS_OK) return status;

maelys_datalog_result_t *result = NULL;
maelys_datalog_diagnostic_t diagnostic = MAELYS_DATALOG_DIAGNOSTIC_INIT;
status = maelys_datalog_session_solve_edb(
    session, edb, &result, &diagnostic);
if (status != MAELYS_DATALOG_STATUS_OK) {
    /* No result was published: deny and inspect diagnostic. */
}

The resulting IDB includes can_read("alice","roadmap.pdf") and allow("alice","roadmap.pdf"); the blocked Mallory has no allow fact. Release this result before solving another request on the same session.

Sessions and repeated solves

A session prepares one policy and may solve multiple independent fact arrays. Each call to maelys_datalog_session_solve() replaces the runtime EDB for that solve; callers do not clear or finalize an exposed EDB structure.

Public fact values are text symbols, signed integers, or booleans:

CODE
maelys_datalog_value_t values[3] = {
    { .kind = MAELYS_DATALOG_VALUE_SYMBOL,  .as.symbol = "alice" },
    { .kind = MAELYS_DATALOG_VALUE_INTEGER, .as.integer = 42 },
    { .kind = MAELYS_DATALOG_VALUE_BOOLEAN, .as.boolean = 1 },
};

The facade performs symbol interning and ground-query conversion internally. New consumers do not need direct access to a symbol table or predicate ID.

Opaque session configuration

Session configuration has been available since 0.4.0. Use it only when the defaults do not express an application's requirements.

Ordinary consumers still include only <maelys/datalog.h>. Use maelys_datalog_session_config_t when you need to require a capability; the default maelys_datalog_session_create() remains unchanged.

Pass the configuration at creation time when you must require capabilities or supply a bounded explanation workspace. A failed requirement prevents the session from being published.

C · functionSince v0.4.0
Create a configured session
maelys_datalog_status_t
maelys_datalog_session_create_configured(
const maelys_datalog_policy_t * policy,
size_t policy_index,
const maelys_datalog_session_config_t * config,
maelys_datalog_session_t ** out_session
);
Prepares one selected policy using an explicit session configuration, including any requested execution and explanation settings.
Arguments
policyconst maelys_datalog_policy_t *
Loaded policy set.
policy_indexsize_t
Policy to prepare within the set.
configconst maelys_datalog_session_config_t *
Requirements copied into the session; NULL means defaults.
out_sessionmaelys_datalog_session_t **
Receives the configured session on success.
Return value
maelys_datalog_status_t

Returns OK with a prepared session, or an error if requirements cannot be met.

This helper requires Why-false support when creating a session for the first policy. It returns an error if the requirement cannot be met:

CODE
#include <maelys/datalog.h>

maelys_datalog_status_t prepare_with_explanations(
    const maelys_datalog_policy_t *policy,
    maelys_datalog_session_t **out)
{
    if (out == NULL) return MAELYS_DATALOG_STATUS_INVALID_ARGUMENT;
    *out = NULL;
    maelys_datalog_session_config_t *config = NULL;
    maelys_datalog_status_t status =
        maelys_datalog_session_config_create(&config);
    if (status != MAELYS_DATALOG_STATUS_OK) return status;

    status = maelys_datalog_session_config_set_required_capabilities(
        config, MAELYS_DATALOG_CAP_EXPLAIN_FALSE);
    if (status == MAELYS_DATALOG_STATUS_OK) {
        status = maelys_datalog_session_create_configured(
            policy, 0u, config, out);
    }
    maelys_datalog_session_config_free(config);
    return status;
}

A new configuration has no additional required capabilities and a zero work budget. Unknown capability bits are rejected without modifying the configuration. A nonzero budget requests enforcement; the current reference backend lacks MAELYS_DATALOG_CAP_WORK_LIMIT, so session creation returns UNSUPPORTED.

Session creation copies the configuration. You may then free it, change it or reuse it without changing existing sessions. A null configuration is equivalent to the default session constructor. Configuration mutation is not synchronized: the caller must serialize access.

The separate datalog_backend.h header remains the extension-author API for implementing a custom backend and using maelys_datalog_session_create_ex(). Its descriptor layout and ABI are unchanged. Applications and Python Next do not need that header to configure a session.

Session identity and release

Use a fingerprint when an audit record or cache must identify the selected policy, rather than just the loaded set. Both functions write into a caller-owned buffer of MAELYS_DATALOG_PUBLIC_FINGERPRINT_BYTES bytes and leave that buffer unchanged on failure.

C · function
Fingerprint the selected policy
maelys_datalog_status_t
maelys_datalog_session_fingerprint(
const maelys_datalog_session_t * session,
char * out_fingerprint
);
Reads the policy identity selected by this session, independently of its execution configuration.
Arguments
sessionconst maelys_datalog_session_t *
Prepared selection to identify.
out_fingerprintchar *
Caller-owned fingerprint buffer of MAELYS_DATALOG_PUBLIC_FINGERPRINT_BYTES bytes.
Return value
maelys_datalog_status_t

Returns OK with the selected policy authority identity; leaves the output unchanged on failure.

C · function
Fingerprint policy and execution
maelys_datalog_status_t
maelys_datalog_session_execution_fingerprint(
const maelys_datalog_session_t * session,
char * out_fingerprint
);
Reads the combined identity of the selected policy and its execution configuration, for distinguishing how a policy is evaluated.
Arguments
sessionconst maelys_datalog_session_t *
Prepared session to identify.
out_fingerprintchar *
Caller-owned fingerprint buffer of MAELYS_DATALOG_PUBLIC_FINGERPRINT_BYTES bytes.
Return value
maelys_datalog_status_t

Returns OK with the policy, backend, execution options and size-profile identity; leaves the output unchanged on failure.

The execution fingerprint adds the backend, execution options and size profile to the policy authority identity. Neither fingerprint includes runtime request facts, so it is not an identifier for a particular decision or input batch.

CODE
char identity[MAELYS_DATALOG_PUBLIC_FINGERPRINT_BYTES];
maelys_datalog_status_t status =
    maelys_datalog_session_execution_fingerprint(session, identity);
if (status != MAELYS_DATALOG_STATUS_OK) {
    /* Do not use identity. */
}

A successful solve gives the session one live result. Release that result before another solve and before freeing the session.

C · function
Release a session
maelys_datalog_status_t
maelys_datalog_session_free(
maelys_datalog_session_t * session
);
Releases a prepared session once its live result has been released.
Arguments
sessionmaelys_datalog_session_t *
Session to release after its result has been freed.
Return value
maelys_datalog_status_t

Returns OK when the session is released; a still-live result prevents release.

CODE
maelys_datalog_status_t status = maelys_datalog_result_free(result);
if (status != MAELYS_DATALOG_STATUS_OK) return status;
result = NULL;
status = maelys_datalog_session_free(session);
if (status != MAELYS_DATALOG_STATUS_OK) return status;
session = NULL;