Files
MetaCrate/docs/extension-milestone-gate.md
Chili Palmer d4990f3b07
All checks were successful
Native code generation / deterministic (push) Successful in 18m9s
Native Rust workspace compile / compile (push) Successful in 21m31s
Complete native extension milestone gate (#84)
2026-08-11 04:41:23 +00:00

5.2 KiB

Rendering, RLV, and LSL extension gate

Milestone 10 replaces the pinned rendering, Restrained Love Viewer, and LSL tooling assemblies with native Rust. The four extension crates are normal workspace dependencies with no opt-in compatibility feature: adding one of them selects its Rust implementation on every supported platform. None loads a CLR assembly, starts a .NET process, or delegates to a platform-only API.

Choosing an extension

Previous C# assembly Rust crate Primary entry points
LibreMetaverse.Rendering.Simple libremetaverse-rendering-simple SimpleRenderer, IRendering
LibreMetaverse.Rendering.MeshFoundry libremetaverse-rendering-mesh-foundry MeshFoundry, IRendering, MeshFaceAux
LibreMetaverse.RLV libremetaverse-rlv RlvService, RlvPermissionsService, callback traits
LibreMetaverse.LslTools libremetaverse-lsl-tools Lexer, Parser, Grammar, generated tables

The mapped PascalCase C# surface remains represented in the API ledger, while the callable Rust names follow the workspace's snake-case mapping. New code should use owned Rust values and Result instead of nullable CLR containers or exceptions. api/SHIM-COVERAGE.md is generated evidence that all 194 types and 1,287 members in these four assemblies are native; the milestone audit rejects an owned not_implemented, unimplemented_api, todo!, or unimplemented!.

Rendering migration

Both renderers consume the native core Primitive and common IRendering types. Use SimpleRenderer for prim and decoded sculpt geometry. Use MeshFoundry when an LLSD mesh asset, skin weights, secondary UVs, tangents, terrain, or physics hulls are required. Both keep coordinates prim-local; the world service remains responsible for object transforms, asset retrieval, and scene ownership.

use libremetaverse::Primitive;
use libremetaverse::rendering::{DetailLevel, IRendering};
use libremetaverse_rendering_simple::SimpleRenderer;

fn render(primitive: Primitive) -> Result<usize, libremetaverse_types::Error> {
    let renderer = SimpleRenderer::new()?;
    Ok(renderer
        .generate_simple_mesh(primitive, DetailLevel::High)?
        .indices
        .len())
}

Inputs are bounded before allocation: a face stays in the 16-bit index domain, and MeshFoundry caps encoded/decompressed assets, sections, total geometry, joints, and convex data. Rendering is deterministic and performs no network, GPU, window-system, or callback work.

RLV host integration and teardown

RlvService separates deterministic protocol/state handling from world side effects. A host implements every required method of IRlvQueryCallbacks and IRlvActionCallbacks, then passes owned trait objects to RlvService::new. There are no generated fallback methods: an incomplete adapter fails to compile. RlvCallbacksDefault and RlvActionCallbacksDefault are complete, cancellation-aware adapters for hosts that intentionally use conservative query values and no-op actions.

use libremetaverse_rlv::{RlvActionCallbacksDefault, RlvCallbacksDefault, RlvService};

fn service() -> Result<RlvService, libremetaverse_types::Error> {
    RlvService::new(
        Box::new(RlvCallbacksDefault::new()?),
        Box::new(RlvActionCallbacksDefault::new()?),
        true,
    )
}

Core/world adapters should snapshot manager data before returning a future and perform network actions through the corresponding manager APIs. The RLV crate releases its locks before awaiting a callback, checks cancellation between commands, bounds each message to 64 KiB and 128 commands, and never starts a background task. Drop event Subscription guards when a host shuts down; drop the service and its callback objects after outstanding host futures complete.

LSL tooling migration

Use generated_lexer() and generated_parser() for the reviewed checked-in grammar, or build typed Dfa and Grammar values for another language. Source locations use UTF-16 code units to preserve the mapped contract. Generation is an explicit development operation; parsing never generates or compiles code at runtime.

use libremetaverse_lsl_tools::{Lexer, Parser, generated_lexer, generated_parser};

fn parse(source: String) -> Result<String, libremetaverse_types::Error> {
    let lexer = Lexer::new(generated_lexer()?)?;
    let mut parser = Parser::new(generated_parser()?, lexer)?;
    Ok(parser.parse_with_string(source)?.yyname())
}

Source, token, DFA, parser-state, stack, operation, recovery, and generator sizes have fixed limits. The checked table is reproducible with python3 tools/generate_lsl_tables.py --check; API generation is checked with python3 tools/generate_api_shims.py --check.

Complete milestone verification

python3 tools/check_milestone_10.py audits native ownership, reviewed parity metadata, deterministic generation, resource limits, integration evidence, migration documentation, and the ubuntu-only workflow. Run python3 tools/test_milestone_10.py to execute the four crate suites, all 616 reviewed RLV compatibility cases, rendering compatibility, the cross-extension core/world integration, and the compile-only mapped API fixture. The workflow runs these gates on ubuntu-latest.