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
| Type | Purpose |
|---|---|
maelys_datalog_predicate_t | One name, arity and set of predicate permissions. |
maelys_datalog_domain_t | A 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.
| Type | Use on this page | Defined in |
|---|---|---|
maelys_datalog_status_t | Return value of maelys_datalog_domain_register(): MAELYS_DATALOG_STATUS_OK on success, an error status otherwise. | Errors |
Functions
| Function | Purpose |
|---|---|
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 macro | Purpose |
|---|---|
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.
typedef struct {
const char *name;
size_t arity;
unsigned flags;
} maelys_datalog_predicate_t;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
| Flag | Meaning |
|---|---|
MAELYS_DATALOG_PREDICATE_EDB | Runtime facts may be supplied for this predicate. |
MAELYS_DATALOG_PREDICATE_IDB | Rules may derive this predicate. |
MAELYS_DATALOG_PREDICATE_POLICY_FACT | Direct facts may be written in policy source. |
MAELYS_DATALOG_PREDICATE_QUERY | The 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:
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;/* 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:
maelys_datalog_status_t
maelys_datalog_domain_register(
const maelys_datalog_domain_t *domain
);maelys_datalog_status_tMAELYS_DATALOG_STATUS_OK on success; otherwise a public error status. Do not load a policy for a domain whose registration failed.
/* 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
MAELYS_DATALOG_EDB(name, arity)Declares a runtime-input predicate.
Constructs a predicate declaration with EDB origin. It does not insert a fact or register the domain.
A predicate initializer with EDB origin.
static const maelys_datalog_predicate_t predicates[] = {
MAELYS_DATALOG_EDB("owns", 2),
};MAELYS_DATALOG_EDB_QUERY(name, arity)Declares a runtime-input predicate that may also be queried.
Constructs an EDB-origin declaration with query permission; it does not insert or query a fact.
A predicate initializer with EDB and QUERY flags.
static const maelys_datalog_predicate_t predicates[] = {
MAELYS_DATALOG_EDB_QUERY("owns", 2),
};MAELYS_DATALOG_IDB(name, arity)Declares a relation derived by policy rules.
Constructs an IDB-origin declaration for rule-derived facts; it does not evaluate rules.
A predicate initializer with IDB origin.
static const maelys_datalog_predicate_t predicates[] = {
MAELYS_DATALOG_IDB("can_read", 2),
};MAELYS_DATALOG_IDB_QUERY(name, arity)Declares a derived relation that may also be queried.
Constructs an IDB-origin declaration with query permission; it does not run a query.
A predicate initializer with IDB and QUERY flags.
static const maelys_datalog_predicate_t predicates[] = {
MAELYS_DATALOG_IDB_QUERY("allow", 2),
};MAELYS_DATALOG_POLICY_FACT(name, arity)Declares a predicate whose ground facts come from policy source.
Constructs a POLICY_FACT-origin declaration; the policy source supplies its facts when loaded.
A predicate initializer with POLICY_FACT origin.
static const maelys_datalog_predicate_t predicates[] = {
MAELYS_DATALOG_POLICY_FACT("trusted", 1),
};MAELYS_DATALOG_POLICY_FACT_QUERY(name, arity)Declares policy-source facts that may also be queried.
Constructs a POLICY_FACT-origin declaration with query permission; it does not add a source fact.
A predicate initializer with POLICY_FACT and QUERY flags.
static const maelys_datalog_predicate_t predicates[] = {
MAELYS_DATALOG_POLICY_FACT_QUERY("trusted", 1),
};MAELYS_DATALOG_DOMAIN_NO_ATOMS(name, predicates)Declares a domain when policy source contains no quoted symbolic constants.
Uses sizeof to count the predicate array and declares zero policy-source atoms. Registration remains a separate call.
A domain initializer with the predicate array count and zero source atoms; registration is a separate call.
const maelys_datalog_domain_t domain =
MAELYS_DATALOG_DOMAIN_NO_ATOMS("documents", predicates);MAELYS_DATALOG_DOMAIN_WITH_ATOMS(name, predicates, atoms)Declares a domain with an explicit array of allowed policy-source atoms.
Uses sizeof to count both arrays. It declares allowed policy-source atoms but does not add facts or register the domain.
A domain initializer with the predicate and atom array counts; registration is a separate call.
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.
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.