nupp.spi
Discover implementations, then choose with ordinary module initialization code.
load(Interface) returns a lazy iterator in dependency order. Iteration order does not choose a winner: the caller may compare priorities, check capabilities, or combine implementations. select is the common rule, the unique highest priority, with the caller's fallback where nothing is advertised:
local spi = require("nupp.spi")
local {type Codec} = require("example.codec.spi")
local impl: Codec = spi.select(spi.load(Codec)) ?? require("example.defaultcodec")Keep the selected functions when the module loads. Packages advertise their implementation modules in nupp/spi.json.
Module contents
Functions
| Function | Kind | Description |
|---|---|---|
load | function | Iterates implementations of an exported interface without choosing one. |
select | function | Chooses the implementation with the unique highest priority. |
Functions#
loadfunction#
load(Interface): function(): Interface?Iterates implementations of an exported interface without choosing one. Call as nupp.spi.load(Interface), passing the interface declaration. Each iteration loads one module; ordinary require caching retains its identity.
Arguments
| Name | Type | Description |
|---|---|---|
Interface | interface declaration | The exported interface whose implementations to discover. |
Returns
| Type | Description |
|---|---|
function(): Interface? | A lazy iterator of implementations, returning nil at exhaustion. |
Raises
| Type | Condition |
|---|---|
any | whatever an implementation raised while loading, which is that module's business rather than this one's; the next call retries it |
selectfunction#
function select<I>(candidates: function(): I?): I?Chooses the implementation with the unique highest priority. Call as nupp.spi.select(nupp.spi.load(Interface)) ?? fallback: nil where nothing is advertised, so the fallback is loaded only when it is used. An implementation that states no priority counts as 0, and a higher priority supersedes a tie below it. Discovery order never breaks a tie for the highest.
Type parameters
| Name | Description |
|---|---|
I |
Arguments
| Name | Type | Description |
|---|---|---|
candidates | function(): I? | The implementations to choose among, usually what |
Returns
| Type | Description |
|---|---|
I? | The implementation with the highest priority, or nil where there is none. |
Raises
| Type | Condition |
|---|---|
string | where two implementations share the highest priority |
any | whatever an implementation raised while loading |