Skip to content

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)
    }
}