Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
arora-module
Write an Arora module in Rust: the crate that implements a module also carries its interface.
Ids are pinned in the attributes, in hex; a parameter is a plain Rust type, or
&mut T when the function writes through it. From that one declaration come:
polly::ids |
the module id, and per function its id and parameter ids |
polly::header(executor) |
the header a module.yaml is written from at export |
polly::record(parent) |
the frozen module record a store serves |
polly::exports() |
every export callable, for HostModule::of::<polly::Module>() |
polly::client::say(&mut bridge, …) |
the typed stub a caller programs against |
arora_function_<id> |
the entry point an executor looks up in the built artifact |
The executor is not the declaration's to name. Only the step that builds
the artifact knows whether it is native or wasm, so header takes it there. A
module linked into the host has no header at all: it is registered from its
exports and described by its record.
The two forms
#[module] goes on an inline Rust module and finds the #[export]
functions itself. For a module in its own file, an attribute macro cannot see
the items, so the file ends with the aggregate naming them:
use ;
declare_module!
Several modules, one set of functions: contracts
A contract declares functions that several modules implement, each under
its own module id: one say, served by a cloud speech provider on one device
and by a local one on another. It is a trait whose methods have no body and
take &mut self, the implementation the host module owns and calls them on:
let module = from_exports;
Beside the trait, the module say (the trait's name in snake case) holds:
say::ids |
per function, its id and parameter ids |
say::NAME |
the contract's name, name = "…" or the module's |
say::descriptions() |
each function's name and frozen signature, by id — how a device describes them, whatever implements them |
say::record(parent) |
the frozen module record of an implementation |
say::exports(implementation) |
every function callable on implementation, for HostModule::from_exports |
Why &mut self
The receiver names the implementation. A trait is implemented for a type, so
an implementation has one whether or not its methods take self; the
receiver adds a value of that type, which the host module owns. An
implementation with no state is a unit struct. It is zero-sized: the value
takes no memory, and nothing is ever read through the reference.
;
let module = from_exports;
An implementation with state keeps it in its fields, and each host module
holds its own value: two devices in one process do not share it. The
reference is &mut because the engine calls a host module's functions one
at a time, with exclusive access, so the implementation changes its fields
without a lock. The alternatives, and why they were not taken, are under
A contract's functions take &mut self in the
design decisions.
rustc checks that each implementation provides every function with its
declared signature. A contract has no artifact entry points: an artifact
exports one module's functions, declared with #[module].
Calling a module that is not a Rust declaration
module_from_header! reads a resolved header at expansion and produces the
same ids and stubs from it:
module_from_header!;
let status = say?;
What a type must be
A parameter or return type is a primitive, a Vec<T> of one, an
arora_types::value::Value (anything, as the dynamic key-value type), or a
type deriving AroraType, which also gives it the
Value conversions and the version a frozen signature pins it at. Maps are
refused: the record vocabulary has no form for them.
An Option<T> of any of those but an array is an optional parameter or
return. A caller may leave an optional argument out, or send
Value::Option(None), and the function receives None. A present argument
arrives wrapped in Value::Option, or as its bare element; either way the
element's type is checked. Any other parameter is required: a call without it
fails, naming the parameter.
Checked at compile time
Two functions of one module or contract cannot share an id or a name, nor two parameters of one function; the build fails naming both. A parameter's name spells its id constant, so it is a Rust identifier.