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

FunctionKindDescription
loadfunctionIterates implementations of an exported interface without choosing one.
selectfunctionChooses 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

NameTypeDescription
Interfaceinterface declaration

The exported interface whose implementations to discover.

Returns

TypeDescription
function(): Interface?

A lazy iterator of implementations, returning nil at exhaustion.

Raises

TypeCondition
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

NameDescription
I

Arguments

NameTypeDescription
candidatesfunction(): I?

The implementations to choose among, usually what load answered.

Returns

TypeDescription
I?

The implementation with the highest priority, or nil where there is none.

Raises

TypeCondition
string

where two implementations share the highest priority

any

whatever an implementation raised while loading