NativeGeometry.kt
src/jvmMain/kotlin/afield/geometry/network/NativeGeometry.kt · 104 lines
package afield.geometry.network
import kotlinx.serialization.Serializable
Which of Field's optional native geometry libraries are installed, and what the welcome page says about the rest.
Morse–Smale complexes, principal curves and polyvector vectorization each need a native library that Field does not build by default. NativeGeometry holds one NativeGeometryCapability per module, registered by that module's own library object, and answers NativeGeometry.available and NativeGeometry.describe without loading any of them, so asking never fails. Field runs without any of them, and calling into one that is absent throws an error naming the Gradle task that builds it.
NativeGeometry.status reports every module as a NativeGeometryStatus, which
GET /api/native-geometry-status serves to the welcome page's Geometry extensions panel:
whether the library loaded, its docs page, its build task, and the shell commands that install
its prerequisites on macOS, Linux and Windows.
interface NativeGeometryCapability
One optional native geometry library, as NativeGeometry sees it. Implementations must answer without loading the library's symbols, so asking never fails.
val name: String
val isAvailable: Boolean
fun describe(): String
One line: where the library was found, or why not and how to build it.
val title: String
A short human title, for the welcome page.
val docsPage: String
The docs page, relative to the docs root (e.g. morse_smale.md).
val buildTask: String
The Gradle task that builds it.
val install: Map<String, List<String>>
Shell commands that install its prerequisites and build it, per OS (macos, linux,
windows). An empty list for an OS means the build does not support it yet.
data class NativeGeometryStatus
One library's state, as GET /api/native-geometry-status reports it to the welcome page.
@Serializable
data class NativeGeometryStatus(
val name: String,
val title: String,
val available: Boolean,
val description: String,
val docsPage: String,
val buildTask: String,
val install: Map<String, List<String>>,
)
object NativeGeometry
Which of Field's optional geometry libraries are installed.
NativeGeometry.available("morseSmale")
NativeGeometry.describe() // every module, one line each
Each module is a separate native library loaded on first use. Field builds and runs without any of them; calling an absent one throws an error that says how to build it.
object NativeGeometry {
private val modules = linkedMapOf<String, () -> NativeGeometryCapability>()
init
init {
// Each entry names a module's library object, which only knows where its file would be;
// nothing is loaded until a module is used.
register("morseSmale") { afield.geometry.topology.morsesmale.MorseSmaleLibrary }
register("principalCurves") { afield.geometry.curves.principal.PrincipalCurvesLibrary }
register("polyvector") { afield.geometry.vectorize.polyvector.PolyvectorLibrary }
}
fun register(name: String, capability: () -> NativeGeometryCapability) {
Called by each module's library object; the factory is evaluated only when asked.
fun register(name: String, capability: () -> NativeGeometryCapability) {
modules[name] = capability
}
val names: Set<String> get() = modules.keys
Module names Field knows about, installed or not.
fun available(name: String): Boolean = modules[name]?.invoke()?.isAvailable ?: false
fun describe(name: String): String
fun describe(name: String): String =
modules[name]?.invoke()?.describe() ?: "$name: not a native geometry module (known: ${names.joinToString()})"
fun describe(): String = names.joinToString("\n") { describe(it) }
fun status(): List<NativeGeometryStatus>
Every module's state, for the welcome page. Never throws: a broken library describes itself.
fun status(): List<NativeGeometryStatus> = modules.values.map { factory ->
val c = factory()
NativeGeometryStatus(c.name, c.title, c.isAvailable, c.describe(), c.docsPage, c.buildTask, c.install)
}
}