shared design
Design goal
Every package of luna_thread needs to say which backend, which mode, how many
workers and what ordering it means, and every backend needs to speak the C
runtime’s integer codes. shared is the one place where these are defined, so
that plan, workflow and the backends agree on them without depending on
each other. It has no dependencies of its own and builds on every target.
Mathematical background
Policies as a refined product
An execution policy is an element of the product
backend, mode, worker count, chunk size and ordering. The v1 runtime accepts the subset
make_execution_policy is a partial constructor : it
returns its argument when it lies in and otherwise the first violated
condition, in the order listed. validate_policy returns the list of all
violated conditions, so
Status codes as a section and a retraction
Let be the eight constructors of NativeStatus and
native_status_code number them to .
Let native_status_from_code invert on
and send every other integer to InvalidArgument. Then
so is injective (a section) and is surjective (a retraction). The other composite is the identity only on the image of :
Converting a C status to NativeStatus and back therefore preserves codes
to and collapses the workflow statuses to to .
Design decisions
Return the first policy error, list all policy issues
Constructing a policy is the common case, and one error message is enough to
fix a call, so make_execution_policy returns Result with the first problem.
Re-checking a stored policy happens inside workflow validation, which reports
everything at once, so validate_policy returns all problems. Both test the
same four conditions in the same order.
Aborting conveniences are kept small
ExecutionPolicy::new, native_policy and javascript_policy unwrap the
result of make_execution_policy. For the native defaults this cannot fail.
For the JavaScript backend it always fails in v1, so javascript_policy
aborts; it exists so that code written for the planned JavaScript backend
compiles today. Code that takes policy arguments from users should call
make_execution_policy.
Capabilities are declared, not probed
RuntimeCapabilities::for_backend returns a fixed table. Probing the running
system would need the native backend, which shared must not depend on, and
would differ between the moon build and the CMake build. The table states the
intended capabilities of each backend; the backend pages state what the current
implementation does.
Integer-coded mirrors of the C structs
NativeBuffer and the three request records copy the field order and integer
encodings of the C structs in luna_thread_runtime.h, so that a binding can
fill them without knowing the typed records of backend/native. The
specification calls this correspondence the ABI layout isomorphism. The records
store values unchecked; checking belongs to the backend that sends them.
Correctness / invariants
- Policy subset. Every policy returned by
make_execution_policy,ExecutionPolicy::newornative_policylies in . - Status round trip. for every
NativeStatus, as derived above; the test in the shared API checks all eight. - No dependencies. The package imports only the MoonBit core library, so the dependency graph of the module stays acyclic.
Alternatives rejected
- A typed error per backend. One
PolicyIssuetype keeps policies backend-independent; the issues name the unsupported backend or mode as data. - A partial
native_status_from_code. ReturningNativeStatus?would force every caller to handle codes the runtime may add later; mapping them toInvalidArgumenterrs on the side of failure. - Defining the integer codes in each backend. The codes are part of the C contract, so they live in the package every backend shares.
Boundaries
The package does not run anything, probe the system, validate the integer request records, or describe statuses to as constructors; the workflow runtime reports those as raw integers.