C Stable API

Registries

Declare and register a closed domain through the stable opaque C API.

Register a domain before loading a policy. The domain lists the predicates that the policy and requests may use: each predicate's name, number of terms, origin and query permission. It may also list string constants allowed in policy source. For the underlying idea, see registries. The stable loader creates the policy's predicate registry from this domain for you; you do not declare a second list of predicates. The registration call keeps those working details behind the opaque API.

Types

Defined on this page

TypePurpose
maelys_datalog_predicate_tOne name, arity and set of predicate permissions.
maelys_datalog_domain_tA named vocabulary containing predicates and optional policy-source atoms.

Return types

This type is used as a return value here; its declaration is defined on the linked page.

TypeUse on this pageDefined in
maelys_datalog_status_tReturn value of maelys_datalog_domain_register(): MAELYS_DATALOG_STATUS_OK on success, an error status otherwise.Errors

Functions

FunctionPurpose
maelys_datalog_domain_register()Register this vocabulary before loading policies.

Function-like macro builders

These macros construct declarations; they do not register a domain. The object-like MAELYS_DATALOG_PREDICATE_* flag constants are explained under Predicate flags, not listed as builders.

Function-like macroPurpose
MAELYS_DATALOG_EDB(name, arity)Declares a runtime-input predicate.
MAELYS_DATALOG_EDB_QUERY(name, arity)Declares a runtime-input predicate that may also be queried.
MAELYS_DATALOG_IDB(name, arity)Declares a relation derived by policy rules.
MAELYS_DATALOG_IDB_QUERY(name, arity)Declares a derived relation that may also be queried.
MAELYS_DATALOG_POLICY_FACT(name, arity)Declares a predicate whose ground facts come from policy source.
MAELYS_DATALOG_POLICY_FACT_QUERY(name, arity)Declares policy-source facts that may also be queried.
MAELYS_DATALOG_DOMAIN_NO_ATOMS(name, predicates)Declares a domain when policy source contains no quoted symbolic constants.
MAELYS_DATALOG_DOMAIN_WITH_ATOMS(name, predicates, atoms)Declares a domain with an explicit array of allowed policy-source atoms.

Declare predicates

Before assembling a domain, describe each predicate with maelys_datalog_predicate_t. One declaration gives the predicate a name, fixes how many terms it has (its arity), and says where its facts may come from and whether callers may query it. The domain then holds an array of these declarations.

C · struct
maelys_datalog_predicate_t
typedef struct {
    const char *name;
    size_t arity;
    unsigned flags;
} maelys_datalog_predicate_t;
One predicate in the domain vocabulary, with a fixed name, arity and set of permissions.
Fields
nameconst char *
Predicate name used by policy rules, facts and queries, such as owns.
aritysize_t
Number of terms in each fact or call; owns(User, Document) has arity 2.
flagsunsigned int
Bitmask declaring the permitted fact origin and optional query permission; the combinations are explained below.
Example
const maelys_datalog_predicate_t owns = {
    "owns", 2u, MAELYS_DATALOG_PREDICATE_EDB,
};

The example declares owns/2 as an EDB predicate: its facts may be supplied with a request. See predicate flags for the other origins and query permission.

Predicate flags

FlagMeaning
MAELYS_DATALOG_PREDICATE_EDBRuntime facts may be supplied for this predicate.
MAELYS_DATALOG_PREDICATE_IDBRules may derive this predicate.
MAELYS_DATALOG_PREDICATE_POLICY_FACTDirect facts may be written in policy source.
MAELYS_DATALOG_PREDICATE_QUERYThe predicate may be queried; combine it with an origin, never use it alone.

The MAELYS_DATALOG_PREDICATE_* names above are flags. Combine an origin with QUERY when callers need to ask whether a fact is present.

Declare a domain

Create a maelys_datalog_domain_t value describing the vocabulary. Its five fields are:

C · struct
maelys_datalog_domain_t
typedef struct {
    const char *name;
    const maelys_datalog_predicate_t *predicates;
    size_t predicate_count;
    const char *const *atoms;
    size_t atom_count;
} maelys_datalog_domain_t;
The domain declaration supplied when registering a policy vocabulary.
Fields
nameconst char *
Name used to select this domain when a policy is loaded.
predicatesconst maelys_datalog_predicate_t *
Array of predicate declarations: names, arities and flags.
predicate_countsize_t
Number of entries in predicates.
atomsconst char *const *
Optional array of literal strings allowed in policy source.
atom_countsize_t
Number of entries in atoms.
Example
/* predicates is the document-access declaration array below. */
const maelys_datalog_domain_t domain = {
    "documents", predicates,
    sizeof(predicates) / sizeof(predicates[0]), NULL, 0u,
};

An atom declaration does not add a fact. A runtime EDB value such as "alice" needs no atom declaration unless that same literal also appears inside policy source. See policy atoms and runtime facts.

Register the domain

Pass the declaration to maelys_datalog_domain_register() before loading a policy:

C · function
Register a domain
maelys_datalog_status_t
maelys_datalog_domain_register(
const maelys_datalog_domain_t *domain
);
Registers a domain: its predicate names, arities, permissions and allowed policy-source atoms. Policies can then be loaded against this vocabulary; registration does not load or evaluate a policy.
Arguments
domainconst maelys_datalog_domain_t *
Domain declaration to register; its name links later policy loads to this vocabulary.
Return value
maelys_datalog_status_t

MAELYS_DATALOG_STATUS_OK on success; otherwise a public error status. Do not load a policy for a domain whose registration failed.

Example
/* domain contains the document-access declarations below. */
maelys_datalog_status_t status = maelys_datalog_domain_register(&domain);
if (status != MAELYS_DATALOG_STATUS_OK) {
    return status;
}
/* Load a policy only after registration succeeds. */

Macro builder reference

C · macro builder
MAELYS_DATALOG_EDB()
MAELYS_DATALOG_EDB(name, arity)

Declares a runtime-input predicate.

Arguments
nameconst char *
Predicate name used in policy source and request facts.
aritysize_t
Number of terms (0–4) in each fact of this predicate.
Effect

Constructs a predicate declaration with EDB origin. It does not insert a fact or register the domain.

Result

A predicate initializer with EDB origin.

Example
static const maelys_datalog_predicate_t predicates[] = {
    MAELYS_DATALOG_EDB("owns", 2),
};
C · macro builder
MAELYS_DATALOG_EDB_QUERY()
MAELYS_DATALOG_EDB_QUERY(name, arity)

Declares a runtime-input predicate that may also be queried.

Arguments
nameconst char *
Queryable runtime-input predicate name.
aritysize_t
Number of terms (0–4) in each fact of this predicate.
Effect

Constructs an EDB-origin declaration with query permission; it does not insert or query a fact.

Result

A predicate initializer with EDB and QUERY flags.

Example
static const maelys_datalog_predicate_t predicates[] = {
    MAELYS_DATALOG_EDB_QUERY("owns", 2),
};
C · macro builder
MAELYS_DATALOG_IDB()
MAELYS_DATALOG_IDB(name, arity)

Declares a relation derived by policy rules.

Arguments
nameconst char *
Name of a relation derived by rules.
aritysize_t
Number of terms (0–4) in each fact of this predicate.
Effect

Constructs an IDB-origin declaration for rule-derived facts; it does not evaluate rules.

Result

A predicate initializer with IDB origin.

Example
static const maelys_datalog_predicate_t predicates[] = {
    MAELYS_DATALOG_IDB("can_read", 2),
};
C · macro builder
MAELYS_DATALOG_IDB_QUERY()
MAELYS_DATALOG_IDB_QUERY(name, arity)

Declares a derived relation that may also be queried.

Arguments
nameconst char *
Name of a queryable relation derived by rules.
aritysize_t
Number of terms (0–4) in each fact of this predicate.
Effect

Constructs an IDB-origin declaration with query permission; it does not run a query.

Result

A predicate initializer with IDB and QUERY flags.

Example
static const maelys_datalog_predicate_t predicates[] = {
    MAELYS_DATALOG_IDB_QUERY("allow", 2),
};
C · macro builder
MAELYS_DATALOG_POLICY_FACT()
MAELYS_DATALOG_POLICY_FACT(name, arity)

Declares a predicate whose ground facts come from policy source.

Arguments
nameconst char *
Name of a predicate populated by policy-source facts.
aritysize_t
Number of terms (0–4) in each fact of this predicate.
Effect

Constructs a POLICY_FACT-origin declaration; the policy source supplies its facts when loaded.

Result

A predicate initializer with POLICY_FACT origin.

Example
static const maelys_datalog_predicate_t predicates[] = {
    MAELYS_DATALOG_POLICY_FACT("trusted", 1),
};
C · macro builder
MAELYS_DATALOG_POLICY_FACT_QUERY()
MAELYS_DATALOG_POLICY_FACT_QUERY(name, arity)

Declares policy-source facts that may also be queried.

Arguments
nameconst char *
Name of a queryable policy-source-fact predicate.
aritysize_t
Number of terms (0–4) in each fact of this predicate.
Effect

Constructs a POLICY_FACT-origin declaration with query permission; it does not add a source fact.

Result

A predicate initializer with POLICY_FACT and QUERY flags.

Example
static const maelys_datalog_predicate_t predicates[] = {
    MAELYS_DATALOG_POLICY_FACT_QUERY("trusted", 1),
};
C · macro builder
MAELYS_DATALOG_DOMAIN_NO_ATOMS()
MAELYS_DATALOG_DOMAIN_NO_ATOMS(name, predicates)

Declares a domain when policy source contains no quoted symbolic constants.

Arguments
nameconst char *
Name identifying the registered domain.
predicatesconst maelys_datalog_predicate_t[N] array
A nonempty fixed-size array; a pointer cannot supply its length via sizeof.
Effect

Uses sizeof to count the predicate array and declares zero policy-source atoms. Registration remains a separate call.

Result

A domain initializer with the predicate array count and zero source atoms; registration is a separate call.

Example
const maelys_datalog_domain_t domain =
    MAELYS_DATALOG_DOMAIN_NO_ATOMS("documents", predicates);
C · macro builder
MAELYS_DATALOG_DOMAIN_WITH_ATOMS()
MAELYS_DATALOG_DOMAIN_WITH_ATOMS(name, predicates, atoms)

Declares a domain with an explicit array of allowed policy-source atoms.

Arguments
nameconst char *
Name identifying the registered domain.
predicatesconst maelys_datalog_predicate_t[N] array
A nonempty fixed-size predicate array, not a pointer.
atomsconst char *const [N] array
A nonempty fixed-size array of policy-source strings, not a pointer.
Effect

Uses sizeof to count both arrays. It declares allowed policy-source atoms but does not add facts or register the domain.

Result

A domain initializer with the predicate and atom array counts; registration is a separate call.

Example
const char *const atoms[] = {"mallory"};
const maelys_datalog_domain_t domain =
    MAELYS_DATALOG_DOMAIN_WITH_ATOMS("documents", predicates, atoms);

Example — document access

This is the domain used throughout the quickstart and the C API pages. The four EDB predicates receive request facts; the three IDB predicates are derived by rules. Only has_any_document and allow are queryable.

Choose either tab: both register the same seven predicates for the same document-access policy.

CODEDocument-access domain

domain.c

#include <maelys/datalog.h>

static const maelys_datalog_predicate_t predicates[] = {
    {"user", 1u, MAELYS_DATALOG_PREDICATE_EDB},
    {"owns", 2u, MAELYS_DATALOG_PREDICATE_EDB},
    {"delegated", 2u, MAELYS_DATALOG_PREDICATE_EDB},
    {"blocked", 1u, MAELYS_DATALOG_PREDICATE_EDB},
    {"can_read", 2u, MAELYS_DATALOG_PREDICATE_IDB},
    {"has_any_document", 1u,
     MAELYS_DATALOG_PREDICATE_IDB | MAELYS_DATALOG_PREDICATE_QUERY},
    {"allow", 2u,
     MAELYS_DATALOG_PREDICATE_IDB | MAELYS_DATALOG_PREDICATE_QUERY},
};

maelys_datalog_status_t register_documents_domain(void) {
    const maelys_datalog_domain_t domain = {
        "documents", predicates,
        sizeof(predicates) / sizeof(predicates[0]), NULL, 0u,
    };
    return maelys_datalog_domain_register(&domain);
}

Both versions declare no policy-source atoms (atoms = NULL, atom_count = 0; the explicit initializer writes NULL, 0u). blocked(User) uses a variable in the policy, while blocked("mallory") is a request fact supplied later through the EDB. Neither requires an atom declaration. Declare a quoted string in atoms only when that literal appears inside the policy source.

The published MAELYS_DATALOG_DOMAIN_NO_ATOMS macro is used in the With macros tab. If the policy contains quoted source constants, declare a fixed atoms[] array and use MAELYS_DATALOG_DOMAIN_WITH_ATOMS("documents", predicates, atoms) instead. Both builders infer array lengths with sizeof, so they require arrays rather than pointers.

Registration and loading

Register the domain before using either stable loader. The loader checks the policy's predicates and literal strings against that declaration. Later, solving checks runtime facts against the selected policy's domain. A failed registration or load returns an error status, not a partly usable policy.

The domain name connects the two operations: inline loading receives it directly, while a manifest selects it by name. Continue with manifests for the loading calls, or rulesets for the returned policy set.